dolibarr 21.0.4
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
6 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
8 * Copyright (C) 2010-2023 Juanjo Menent <jmenent@2byte.es>
9 * Copyright (C) 2010-2022 Philippe Grand <philippe.grand@atoo-net.com>
10 * Copyright (C) 2012-2023 Christophe Battarel <christophe.battarel@altairis.fr>
11 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
13 * Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
14 * Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
16 * Copyright (C) 2020 Nicolas ZABOURI <info@inovea-conseil.com>
17 * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
18 * Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
19 * Copyright (C) 2023 William Mead <william.mead@manchenumerique.fr>
20 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
21 * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
22 *
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 3 of the License, or
26 * (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program. If not, see <https://www.gnu.org/licenses/>.
35 */
36
37
44// Load Dolibarr environment
45require '../../main.inc.php';
46require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
47require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
48require_once DOL_DOCUMENT_ROOT.'/core/class/html.formpropal.class.php';
49require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php';
50require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
51require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
52require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php';
53require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php';
54require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
55require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
56require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
57if (isModEnabled('project')) {
58 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
59 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
60}
61
62if (isModEnabled('variants')) {
63 require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination.class.php';
64}
65
75// Load translation files required by the page
76$langs->loadLangs(array('companies', 'propal', 'compta', 'bills', 'orders', 'products', 'deliveries', 'sendings', 'other'));
77if (isModEnabled('incoterm')) {
78 $langs->load('incoterm');
79}
80if (isModEnabled('margin')) {
81 $langs->load('margins');
82}
83
84$error = 0;
85$outlangs = null;
86$array_options = array();
87
88$id = GETPOSTINT('id');
89$ref = GETPOST('ref', 'alpha');
90$socid = GETPOSTINT('socid');
91$action = GETPOST('action', 'aZ09');
92$cancel = GETPOST('cancel', 'alpha');
93$origin = GETPOST('origin', 'alpha');
94$originid = GETPOSTINT('originid');
95$confirm = GETPOST('confirm', 'alpha');
96$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
97$lineid = GETPOSTINT('lineid');
98$contactid = GETPOSTINT('contactid');
99$projectid = GETPOSTINT('projectid');
100$rank = (GETPOSTINT('rank') > 0) ? GETPOSTINT('rank') : -1;
101
102// PDF
103$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
104$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
105$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
106
107$object = new Propal($db);
108$extrafields = new ExtraFields($db);
109
110// fetch optionals attributes and labels
111$extrafields->fetch_name_optionals_label($object->table_element);
112
113// Load object
114if ($id > 0 || !empty($ref)) {
115 $ret = $object->fetch($id, $ref);
116 if ($ret > 0) {
117 $ret = $object->fetch_thirdparty();
118 if ($ret > 0 && isset($object->fk_project)) {
119 $ret = $object->fetchProject();
120 }
121 }
122 if ($ret <= 0) {
123 setEventMessages($object->error, $object->errors, 'errors');
124 $action = '';
125 }
126}
127
128// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
129$hookmanager->initHooks(array('propalcard', 'globalcard'));
130
131$usercanread = $user->hasRight("propal", "lire");
132$usercancreate = $user->hasRight("propal", "creer");
133$usercandelete = $user->hasRight("propal", "supprimer");
134
135$usercanclose = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'close')));
136$usercanvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'validate')));
137$usercansend = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'send')));
138
139$usermustrespectpricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
140$usercancreateorder = ($user->hasRight('commande', 'creer') == 1);
141$usercancreateinvoice = ($user->hasRight('facture', 'creer') == 1);
142$usercancreatecontract = ($user->hasRight('contrat', 'creer') == 1);
143$usercancreateintervention = ($user->hasRight('ficheinter', 'creer') == 1);
144$usercancreatepurchaseorder = ($user->hasRight('fournisseur', 'commande', 'creer') || $user->hasRight('supplier_order', 'creer'));
145
146$permissionnote = $usercancreate; // Used by the include of actions_setnotes.inc.php
147$permissiondellink = $usercancreate; // Used by the include of actions_dellink.inc.php
148$permissiontoedit = $usercancreate; // Used by the include of actions_lineupdown.inc.php
149
150$price_base_type = null;
151
152// Security check
153if (!empty($user->socid)) {
154 $socid = $user->socid;
155}
156restrictedArea($user, 'propal', $object->id);
157
158
159/*
160 * Actions
161 */
162
163$parameters = array('socid' => $socid);
164$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
165if ($reshook < 0) {
166 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
167}
168if (empty($reshook)) {
169 $backurlforlist = DOL_URL_ROOT.'/comm/propal/list.php';
170
171 if (empty($backtopage) || ($cancel && empty($id))) {
172 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
173 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
174 $backtopage = $backurlforlist;
175 } else {
176 $backtopage = DOL_URL_ROOT.'/comm/propal/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
177 }
178 }
179 }
180
181 if ($cancel) {
182 if (!empty($backtopageforcancel)) {
183 header("Location: ".$backtopageforcancel);
184 exit;
185 } elseif (!empty($backtopage)) {
186 header("Location: ".$backtopage);
187 exit;
188 }
189 $action = '';
190 }
191
192 include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once
193
194 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
195
196 include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be 'include', not 'include_once'
197
198 // Action clone object
199 if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
200 if (!($socid > 0)) {
201 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('IdThirdParty')), null, 'errors');
202 } else {
203 if ($object->id > 0) {
204 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY')) {
205 //Get difference between old and new delivery date and change lines according to difference
206 $date_delivery = dol_mktime(
207 12,
208 0,
209 0,
210 GETPOSTINT('date_deliverymonth'),
211 GETPOSTINT('date_deliveryday'),
212 GETPOSTINT('date_deliveryyear')
213 );
214 $date_delivery_old = $object->delivery_date;
215 if (!empty($date_delivery_old) && !empty($date_delivery)) {
216 //Attempt to get the date without possible hour rounding errors
217 $old_date_delivery = dol_mktime(
218 12,
219 0,
220 0,
221 (int) dol_print_date($date_delivery_old, '%m'),
222 (int) dol_print_date($date_delivery_old, '%d'),
223 (int) dol_print_date($date_delivery_old, '%Y')
224 );
225 //Calculate the difference and apply if necessary
226 $difference = $date_delivery - $old_date_delivery;
227 if ($difference != 0) {
228 $object->delivery_date = $date_delivery;
229 foreach ($object->lines as $line) {
230 if (isset($line->date_start)) {
231 $line->date_start += $difference;
232 }
233 if (isset($line->date_end)) {
234 $line->date_end += $difference;
235 }
236 }
237 }
238 }
239 }
240
241 $result = $object->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOSTINT('entity') : null), (GETPOST('update_prices') == 'on'), (GETPOST('update_desc') == 'on'));
242 if ($result > 0) {
243 $warningMsgLineList = array();
244 // check all product lines are to sell otherwise add a warning message for each product line is not to sell
245 foreach ($object->lines as $line) {
246 if (!is_object($line->product)) {
247 $line->fetch_product();
248 }
249 if (is_object($line->product) && $line->product->id > 0) {
250 if (empty($line->product->status)) {
251 $warningMsgLineList[$line->id] = $langs->trans('WarningLineProductNotToSell', $line->product->ref);
252 }
253 }
254 }
255 if (!empty($warningMsgLineList)) {
256 setEventMessages('', $warningMsgLineList, 'warnings');
257 }
258
259 header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result);
260 exit();
261 } else {
262 if (count($object->errors) > 0) {
263 setEventMessages($object->error, $object->errors, 'errors');
264 }
265 $action = '';
266 }
267 }
268 }
269 } elseif ($action == 'confirm_cancel' && $confirm == 'yes' && $usercanclose) {
270 // Cancel proposal
271 $result = $object->setCancel($user);
272 if ($result > 0) {
273 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
274 exit();
275 } else {
276 $langs->load("errors");
277 setEventMessages($object->error, $object->errors, 'errors');
278 }
279 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
280 // Delete proposal
281 $result = $object->delete($user);
282 if ($result > 0) {
283 header('Location: '.DOL_URL_ROOT.'/comm/propal/list.php?restore_lastsearch_values=1');
284 exit();
285 } else {
286 $langs->load("errors");
287 setEventMessages($object->error, $object->errors, 'errors');
288 }
289 } elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
290 // Remove line
291 $result = $object->deleteLine($lineid);
292 // reorder lines
293 if ($result > 0) {
294 $object->line_order(true);
295 } else {
296 $langs->load("errors");
297 setEventMessages($object->error, $object->errors, 'errors');
298 }
299
300 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
301 // Define output language
302 $outputlangs = $langs;
303 if (getDolGlobalInt('MAIN_MULTILANGS')) {
304 $outputlangs = new Translate("", $conf);
305 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
306 $outputlangs->setDefaultLang($newlang);
307 }
308 $ret = $object->fetch($id); // Reload to get new records
309 if ($ret > 0) {
310 $object->fetch_thirdparty();
311 }
312 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
313 }
314
315 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
316 exit();
317 } elseif ($action == 'confirm_validate' && $confirm == 'yes' && $usercanvalidate) {
318 // Validation
319 $idwarehouse = GETPOSTINT('idwarehouse');
320 $result = $object->valid($user);
321 if ($result > 0 && getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
322 $result = $object->closeProposal($user, $object::STATUS_SIGNED);
323 }
324 if ($result >= 0) {
325 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
326 $outputlangs = $langs;
327 $newlang = '';
328 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
329 $newlang = GETPOST('lang_id', 'aZ09');
330 }
331 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
332 $newlang = $object->thirdparty->default_lang;
333 }
334 if (!empty($newlang)) {
335 $outputlangs = new Translate("", $conf);
336 $outputlangs->setDefaultLang($newlang);
337 }
338 $model = $object->model_pdf;
339 $ret = $object->fetch($id); // Reload to get new records
340 if ($ret > 0) {
341 $object->fetch_thirdparty();
342 }
343
344 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
345 }
346 } else {
347 $langs->load("errors");
348 if (count($object->errors) > 0) {
349 setEventMessages($object->error, $object->errors, 'errors');
350 } else {
351 setEventMessages($langs->trans($object->error), null, 'errors');
352 }
353 }
354 } elseif ($action == 'setdate' && $usercancreate) {
355 $datep = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
356
357 if (empty($datep)) {
358 $error++;
359 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
360 }
361
362 if (!$error) {
363 $result = $object->set_date($user, $datep);
364 if ($result > 0 && !empty($object->duree_validite) && !empty($object->fin_validite)) {
365 $datev = $datep + ($object->duree_validite * 24 * 3600);
366 $result = $object->set_echeance($user, $datev, 1);
367 }
368 if ($result < 0) {
369 dol_print_error($db, $object->error);
370 } elseif (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
371 $outputlangs = $langs;
372 $newlang = '';
373 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
374 $newlang = GETPOST('lang_id', 'aZ09');
375 }
376 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
377 $newlang = $object->thirdparty->default_lang;
378 }
379 if (!empty($newlang)) {
380 $outputlangs = new Translate("", $conf);
381 $outputlangs->setDefaultLang($newlang);
382 }
383 $model = $object->model_pdf;
384 $ret = $object->fetch($id); // Reload to get new records
385 if ($ret > 0) {
386 $object->fetch_thirdparty();
387 }
388
389 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
390 }
391 }
392 } elseif ($action == 'setecheance' && $usercancreate) {
393 $result = $object->set_echeance($user, dol_mktime(12, 0, 0, GETPOSTINT('echmonth'), GETPOSTINT('echday'), GETPOSTINT('echyear')));
394 if ($result >= 0) {
395 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
396 $outputlangs = $langs;
397 $newlang = '';
398 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
399 $newlang = GETPOST('lang_id', 'aZ09');
400 }
401 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
402 $newlang = $object->thirdparty->default_lang;
403 }
404 if (!empty($newlang)) {
405 $outputlangs = new Translate("", $conf);
406 $outputlangs->setDefaultLang($newlang);
407 }
408 $model = $object->model_pdf;
409 $ret = $object->fetch($id); // Reload to get new records
410 if ($ret > 0) {
411 $object->fetch_thirdparty();
412 }
413
414 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
415 }
416 } else {
417 setEventMessages($object->error, $object->errors, 'errors');
418 }
419 } elseif ($action == 'setdate_livraison' && $usercancreate) {
420 $result = $object->setDeliveryDate($user, dol_mktime(12, 0, 0, GETPOSTINT('date_livraisonmonth'), GETPOSTINT('date_livraisonday'), GETPOSTINT('date_livraisonyear')));
421 if ($result < 0) {
422 dol_print_error($db, $object->error);
423 }
424 } elseif ($action == 'setref_client' && $usercancreate) {
425 // Positionne ref client
426 $result = $object->set_ref_client($user, GETPOST('ref_client'));
427 if ($result < 0) {
428 setEventMessages($object->error, $object->errors, 'errors');
429 }
430 } elseif ($action == 'set_incoterms' && isModEnabled('incoterm') && $usercancreate) {
431 // Set incoterm
432 $result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOST('location_incoterms'));
433 } elseif ($action == 'add' && $usercancreate) {
434 // Create proposal
435 $object->socid = $socid;
436 $object->fetch_thirdparty();
437
438 $datep = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
439 $date_delivery = dol_mktime(12, 0, 0, GETPOSTINT('date_livraisonmonth'), GETPOSTINT('date_livraisonday'), GETPOSTINT('date_livraisonyear'));
440 $duration = GETPOSTINT('duree_validite');
441
442 if (empty($datep)) {
443 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("DatePropal")), null, 'errors');
444 $action = 'create';
445 $error++;
446 }
447 if (empty($duration)) {
448 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ValidityDuration")), null, 'errors');
449 $action = 'create';
450 $error++;
451 }
452
453 if ($socid < 1) {
454 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Customer")), null, 'errors');
455
456 $action = 'create';
457 $error++;
458 }
459
460 if (!$error) {
461 $db->begin();
462
463 // If we select proposal to clone during creation (when option PROPAL_CLONE_ON_CREATE_PAGE is on)
464 if (GETPOST('createmode') == 'copy' && GETPOST('copie_propal')) {
465 if ($object->fetch(GETPOSTINT('copie_propal')) > 0) {
466 $object->ref = GETPOST('ref');
467 $object->datep = $datep;
468 $object->date = $datep;
469 $object->delivery_date = $date_delivery;
470 $object->availability_id = GETPOSTINT('availability_id');
471 $object->demand_reason_id = GETPOSTINT('demand_reason_id');
472 $object->fk_delivery_address = GETPOSTINT('fk_address');
473 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
474 $object->warehouse_id = GETPOSTINT('warehouse_id');
475 $object->duree_validite = $duration;
476 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
477 $object->deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
478 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
479 $object->fk_account = GETPOSTINT('fk_account');
480 $object->socid = GETPOSTINT('socid');
481 $object->contact_id = GETPOSTINT('contactid');
482 $object->fk_project = GETPOSTINT('projectid');
483 $object->model_pdf = GETPOST('model', 'alphanohtml');
484 $object->author = $user->id; // deprecated
485 $object->user_author_id = $user->id;
486 $object->note_private = GETPOST('note_private', 'restricthtml');
487 $object->note_public = GETPOST('note_public', 'restricthtml');
490 $object->fk_incoterms = GETPOSTINT('incoterm_id');
491 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
492 } else {
493 setEventMessages($langs->trans("ErrorFailedToCopyProposal", GETPOST('copie_propal')), null, 'errors');
494 }
495 } else {
496 $object->ref = GETPOST('ref');
497 $object->ref_client = GETPOST('ref_client');
498 $object->datep = $datep;
499 $object->date = $datep;
500 $object->delivery_date = $date_delivery;
501 $object->availability_id = GETPOSTINT('availability_id');
502 $object->demand_reason_id = GETPOSTINT('demand_reason_id');
503 $object->fk_delivery_address = GETPOSTINT('fk_address');
504 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
505 $object->warehouse_id = GETPOSTINT('warehouse_id');
506 $object->duree_validite = price2num(GETPOST('duree_validite', 'alpha'));
507 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
508 $object->deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
509 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
510 $object->fk_account = GETPOSTINT('fk_account');
511 $object->contact_id = GETPOSTINT('contactid');
512 $object->fk_project = GETPOSTINT('projectid');
513 $object->model_pdf = GETPOST('model');
514 $object->author = $user->id; // deprecated
515 $object->note_private = GETPOST('note_private', 'restricthtml');
516 $object->note_public = GETPOST('note_public', 'restricthtml');
517 $object->fk_incoterms = GETPOSTINT('incoterm_id');
518 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
519
520 $object->origin = GETPOST('origin');
521 $object->origin_id = GETPOSTINT('originid');
522
523 // Multicurrency
524 if (isModEnabled("multicurrency")) {
525 $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
526 }
527
528 // Fill array 'array_options' with data from add form
529 $ret = $extrafields->setOptionalsFromPost(null, $object);
530 if ($ret < 0) {
531 $error++;
532 $action = 'create';
533 }
534 }
535
536 if (!$error) {
537 if ($origin && $originid) {
538 // Parse element/subelement (ex: project_task)
539 $element = $subelement = $origin;
540 $regs = array();
541 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
542 $element = $regs[1];
543 $subelement = $regs[2];
544 }
545
546 // For compatibility
547 if ($element == 'order') {
548 $element = $subelement = 'commande';
549 }
550 if ($element == 'propal') {
551 $element = 'comm/propal';
552 $subelement = 'propal';
553 }
554 if ($element == 'contract') {
555 $element = $subelement = 'contrat';
556 }
557 if ($element == 'inter') {
558 $element = $subelement = 'fichinter';
559 }
560 if ($element == 'shipping') {
561 $element = $subelement = 'expedition';
562 }
563
564 $object->origin = $origin;
565 $object->origin_id = $originid;
566
567 // Possibility to add external linked objects with hooks
568 $object->linked_objects[$object->origin] = $object->origin_id;
569 if (GETPOSTISARRAY('other_linked_objects')) {
570 $object->linked_objects = array_merge($object->linked_objects, GETPOST('other_linked_objects', 'array:int'));
571 }
572
573 $id = $object->create($user);
574 if ($id > 0) {
575 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
576
577 $classname = ucfirst($subelement);
578 $srcobject = new $classname($db);
579 '@phan-var-force Commande|Propal|Contrat|Fichinter|Expedition $srcobject'; // Can be other class, but CommonObject is too generic
580
581 dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines");
582 $result = $srcobject->fetch($object->origin_id);
583
584 if ($result > 0) {
585 $lines = $srcobject->lines;
586 if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
587 $srcobject->fetch_lines();
588 $lines = $srcobject->lines;
589 }
590
591 $fk_parent_line = 0;
592 $num = count($lines);
593 for ($i = 0; $i < $num; $i++) {
594 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
595 $desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : '');
596
597 // Positive line
598 $product_type = ($lines[$i]->product_type ? (int) $lines[$i]->product_type : 0);
599
600 // Date start
601 $date_start = false;
602 if ($lines[$i]->date_debut_prevue) {
603 $date_start = $lines[$i]->date_debut_prevue;
604 }
605 if ($lines[$i]->date_debut_reel) {
606 $date_start = $lines[$i]->date_debut_reel;
607 }
608 if ($lines[$i]->date_start) {
609 $date_start = $lines[$i]->date_start;
610 }
611
612 // Date end
613 $date_end = false;
614 if ($lines[$i]->date_fin_prevue) {
615 $date_end = $lines[$i]->date_fin_prevue;
616 }
617 if ($lines[$i]->date_fin_reel) {
618 $date_end = $lines[$i]->date_fin_reel;
619 }
620 if ($lines[$i]->date_end) {
621 $date_end = $lines[$i]->date_end;
622 }
623
624 // Reset fk_parent_line for no child products and special product
625 if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
626 $fk_parent_line = 0;
627 }
628
629 // Extrafields
630 if (method_exists($lines[$i], 'fetch_optionals')) {
631 $lines[$i]->fetch_optionals();
632 $array_options = $lines[$i]->array_options;
633 }
634
635 $tva_tx = $lines[$i]->tva_tx;
636 if (!empty($lines[$i]->vat_src_code) && !preg_match('/\‍(/', $tva_tx)) {
637 $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
638 }
639
640 $result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, 'HT', 0, $lines[$i]->info_bits, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $date_start, $date_end, $array_options, $lines[$i]->fk_unit);
641
642 if ($result > 0) {
643 $lineid = $result;
644 } else {
645 $lineid = 0;
646 $error++;
647 break;
648 }
649
650 // Defined the new fk_parent_line
651 if ($result > 0 && $lines[$i]->product_type == 9) {
652 $fk_parent_line = $result;
653 }
654 }
655
656 // Hooks
657 $parameters = array('objFrom' => $srcobject);
658 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
659 // modified by hook
660 if ($reshook < 0) {
661 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
662 $error++;
663 }
664 } else {
665 setEventMessages($srcobject->error, $srcobject->errors, 'errors');
666 $error++;
667 }
668 } else {
669 setEventMessages($object->error, $object->errors, 'errors');
670 $error++;
671 }
672 } else {
673 // Standard creation
674 $id = $object->create($user);
675 }
676
677 if ($id > 0) {
678 // Insert default contacts if defined
679 if (GETPOST('contactid') > 0) {
680 $result = $object->add_contact(GETPOST('contactid'), 'CUSTOMER', 'external');
681 if ($result < 0) {
682 $error++;
683 setEventMessages($langs->trans("ErrorFailedToAddContact"), null, 'errors');
684 }
685 }
686
687 if (getDolGlobalString('PROPOSAL_AUTO_ADD_AUTHOR_AS_CONTACT')) {
688 $result = $object->add_contact($user->id, 'SALESREPFOLL', 'internal');
689 if ($result < 0) {
690 $error++;
691 setEventMessages($langs->trans("ErrorFailedToAddUserAsContact"), null, 'errors');
692 }
693 }
694
695 if (!$error) {
696 $db->commit();
697
698 // Define output language
699 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
700 $outputlangs = $langs;
701 $newlang = '';
702 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
703 $newlang = GETPOST('lang_id', 'aZ09');
704 }
705 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
706 $newlang = $object->thirdparty->default_lang;
707 }
708 if (!empty($newlang)) {
709 $outputlangs = new Translate("", $conf);
710 $outputlangs->setDefaultLang($newlang);
711 }
712 $model = $object->model_pdf;
713
714 $ret = $object->fetch($id); // Reload to get new records
715 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
716 if ($result < 0) {
717 dol_print_error($db, $object->error, $object->errors);
718 }
719 }
720
721 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
722 exit();
723 } else {
724 $db->rollback();
725 $action = 'create';
726 }
727 } else {
728 setEventMessages($object->error, $object->errors, 'errors');
729 $db->rollback();
730 $action = 'create';
731 }
732 }
733 }
734 } elseif ($action == 'classifybilled' && $usercanclose) {
735 // Classify billed
736 $db->begin();
737
738 $result = $object->classifyBilled($user, 0, '');
739 if ($result < 0) {
740 setEventMessages($object->error, $object->errors, 'errors');
741 $error++;
742 }
743
744 if (!$error) {
745 $db->commit();
746 } else {
747 $db->rollback();
748 }
749 } elseif ($action == 'confirm_closeas' && $usercanclose && !GETPOST('cancel', 'alpha')) {
750 // Close proposal
751 if (!(GETPOSTINT('statut') > 0)) {
752 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CloseAs")), null, 'errors');
753 $action = 'closeas';
754 } elseif (GETPOSTINT('statut') == $object::STATUS_SIGNED || GETPOSTINT('statut') == $object::STATUS_NOTSIGNED) {
755 $locationTarget = '';
756 // prevent browser refresh from closing proposal several times
757 if ($object->status == $object::STATUS_VALIDATED || (getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE') && $object->status == $object::STATUS_DRAFT)) {
758 $db->begin();
759
760 $oldstatus = $object->status;
761
762 $result = $object->closeProposal($user, GETPOSTINT('statut'), GETPOST('note_private'));
763
764 if ($result < 0) {
765 setEventMessages($object->error, $object->errors, 'errors');
766 $error++;
767 } else {
768 // Needed if object linked modified by trigger (because linked objects can't be fetched two times : linkedObjectsFullLoaded)
769 $locationTarget = DOL_URL_ROOT . '/comm/propal/card.php?id=' . $object->id;
770 }
771
772 $deposit = null;
773
774 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
775
776 if (
777 !$error && GETPOSTINT('statut') == $object::STATUS_SIGNED && GETPOST('generate_deposit') == 'on'
778 && !empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')
779 ) {
780 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
781
782 $date = dol_mktime(0, 0, 0, GETPOSTINT('datefmonth'), GETPOSTINT('datefday'), GETPOSTINT('datefyear'));
783 $forceFields = array();
784
785 if (GETPOSTISSET('date_pointoftax')) {
786 $forceFields['date_pointoftax'] = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'));
787 }
788
789 $deposit = Facture::createDepositFromOrigin($object, $date, GETPOSTINT('cond_reglement_id'), $user, 0, GETPOSTINT('validate_generated_deposit') == 'on', $forceFields);
790
791 if ($deposit) {
792 setEventMessage('DepositGenerated');
793 $locationTarget = DOL_URL_ROOT . '/compta/facture/card.php?id=' . $deposit->id;
794 } else {
795 $error++;
796 setEventMessages("Failed to create down payment - ".$object->error, $object->errors, 'errors');
797 }
798 }
799
800 if (!$error) {
801 $db->commit();
802
803 if ($deposit && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
804 $ret = $deposit->fetch($deposit->id); // Reload to get new records
805 $outputlangs = $langs;
806
807 if (getDolGlobalInt('MAIN_MULTILANGS')) {
808 $outputlangs = new Translate('', $conf);
809 $outputlangs->setDefaultLang($deposit->thirdparty->default_lang);
810 $outputlangs->load('products');
811 }
812
813 $result = $deposit->generateDocument($deposit->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
814
815 if ($result < 0) {
816 setEventMessages($deposit->error, $deposit->errors, 'errors');
817 }
818 }
819
820 if ($locationTarget) {
821 header('Location: ' . $locationTarget);
822 exit;
823 }
824 } else {
825 $object->status = $oldstatus;
826 $object->statut = $oldstatus;
827
828 $db->rollback();
829 $action = '';
830 }
831 }
832 }
833 } elseif ($action == 'confirm_reopen' && $usercanclose && !GETPOST('cancel', 'alpha')) {
834 // Reopen proposal
835 // prevent browser refresh from reopening proposal several times
837 $db->begin();
838
839 $newstatus = (getDolGlobalInt('PROPAL_SKIP_ACCEPT_REFUSE') ? Propal::STATUS_DRAFT : Propal::STATUS_VALIDATED);
840 $result = $object->reopen($user, $newstatus);
841 if ($result < 0) {
842 setEventMessages($object->error, $object->errors, 'errors');
843 $error++;
844 } else {
845 $object->statut = $newstatus;
846 $object->status = $newstatus;
847 }
848
849 if (!$error) {
850 $db->commit();
851 } else {
852 $db->rollback();
853 }
854 }
855 } elseif ($action == 'import_lines_from_object' && $usercancreate && $object->status == Propal::STATUS_DRAFT) {
856 // add lines from objectlinked
857 $fromElement = GETPOST('fromelement');
858 $fromElementid = GETPOST('fromelementid');
859 $importLines = GETPOST('line_checkbox');
860
861 if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
862 if ($fromElement == 'commande') {
863 dol_include_once('/'.$fromElement.'/class/'.$fromElement.'.class.php');
864 $lineClassName = 'OrderLine';
865 } elseif ($fromElement == 'propal') {
866 dol_include_once('/comm/'.$fromElement.'/class/'.$fromElement.'.class.php');
867 $lineClassName = 'PropaleLigne';
868 } elseif ($fromElement == 'facture') {
869 dol_include_once('/compta/'.$fromElement.'/class/'.$fromElement.'.class.php');
870 $lineClassName = 'FactureLigne';
871 } else {
872 $lineClassName = null;
873 }
874 $nextRang = count($object->lines) + 1;
875 $importCount = 0;
876 $error = 0;
877 foreach ($importLines as $lineId) {
878 $lineId = intval($lineId);
879 $originLine = new $lineClassName($db);
880 if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
881 $originLine->fetch_optionals();
882 $desc = $originLine->desc;
883 $pu_ht = $originLine->subprice;
884 $qty = $originLine->qty;
885 $txtva = $originLine->tva_tx;
886 $txlocaltax1 = $originLine->localtax1_tx;
887 $txlocaltax2 = $originLine->localtax2_tx;
888 $fk_product = $originLine->fk_product;
889 $remise_percent = $originLine->remise_percent;
890 $date_start = $originLine->date_start;
891 $date_end = $originLine->date_end;
892 $fk_code_ventilation = 0;
893 $info_bits = $originLine->info_bits;
894 $fk_remise_except = $originLine->fk_remise_except;
895 $price_base_type = 'HT';
896 $pu_ttc = 0;
897 $type = $originLine->product_type;
898 $rang = $nextRang++;
899 $special_code = $originLine->special_code;
900 $origin = $originLine->element;
901 $origin_id = $originLine->id;
902 $fk_parent_line = 0;
903 $fk_fournprice = $originLine->fk_fournprice;
904 $pa_ht = $originLine->pa_ht;
905 $label = $originLine->label;
906 $array_options = $originLine->array_options;
907 $situation_percent = 100;
908 $fk_prev_id = '';
909 $fk_unit = $originLine->fk_unit;
910 $pu_ht_devise = $originLine->multicurrency_subprice;
911
912 $res = $object->addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1, $txlocaltax2, $fk_product, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, $rang, $special_code, $fk_parent_line, $fk_fournprice, $pa_ht, $label, $date_start, $date_end, $array_options, $fk_unit, $origin, $origin_id, $pu_ht_devise, $fk_remise_except);
913
914 if ($res > 0) {
915 $importCount++;
916 } else {
917 $error++;
918 }
919 } else {
920 $error++;
921 }
922 }
923
924 if ($error) {
925 setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
926 }
927 }
928 }
929
930 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
931
932 // Actions to send emails
933 $actiontypecode = 'AC_OTH_AUTO';
934 $triggersendname = 'PROPAL_SENTBYMAIL';
935 $autocopy = 'MAIN_MAIL_AUTOCOPY_PROPOSAL_TO';
936 $trackid = 'pro'.$object->id;
937 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
938
939
940 // Go back to draft
941 if ($action == 'modif' && $usercancreate) {
942 $result = $object->setDraft($user);
943 if ($result < 0) {
944 setEventMessages($object->error, $object->errors, 'errors');
945 }
946
947 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
948 // Define output language
949 $outputlangs = $langs;
950 if (getDolGlobalInt('MAIN_MULTILANGS')) {
951 $outputlangs = new Translate("", $conf);
952 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
953 $outputlangs->setDefaultLang($newlang);
954 }
955 $ret = $object->fetch($id); // Reload to get new records
956 if ($ret > 0) {
957 $object->fetch_thirdparty();
958 }
959 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
960 }
961 } elseif ($action == "setabsolutediscount" && $usercancreate) {
962 if (GETPOSTINT("remise_id")) {
963 if ($object->id > 0) {
964 $result = $object->insert_discount(GETPOSTINT("remise_id"));
965 if ($result < 0) {
966 setEventMessages($object->error, $object->errors, 'errors');
967 }
968 }
969 }
970 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'aZ09') && (GETPOST('alldate_start', 'alpha') || GETPOST('alldate_end', 'alpha')) && $usercancreate) {
971 // Define date start and date end for all line
972 $alldate_start = dol_mktime(GETPOSTINT('alldate_starthour'), GETPOSTINT('alldate_startmin'), 0, GETPOSTINT('alldate_startmonth'), GETPOSTINT('alldate_startday'), GETPOSTINT('alldate_startyear'));
973 $alldate_end = dol_mktime(GETPOSTINT('alldate_endhour'), GETPOSTINT('alldate_endmin'), 0, GETPOSTINT('alldate_endmonth'), GETPOSTINT('alldate_endday'), GETPOSTINT('alldate_endyear'));
974 foreach ($object->lines as $key => $line) {
975 if ($line->product_type == 1) { // only service line
976 $result = $object->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $alldate_start, $alldate_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
977 $object->lines[$key] = $object->line;
978 }
979 }
980 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
981 // Define a vat_rate for all lines
982 $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
983 $vat_rate = str_replace('*', '', $vat_rate);
984 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
985 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
986 foreach ($object->lines as $key => $line) {
987 $result = $object->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
988 $object->lines[$key] = $object->line;
989 }
990 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
991 // Define a discount for all lines
992 $remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
993 $remise_percent = str_replace('*', '', $remise_percent);
994 foreach ($object->lines as $key => $line) {
995 $tvatx = $line->tva_tx;
996 if (!empty($line->vat_src_code)) {
997 $tvatx .= ' ('.$line->vat_src_code.')';
998 }
999 $result = $object->updateline($line->id, $line->subprice, $line->qty, $remise_percent, $tvatx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
1000 $object->lines[$key] = $object->line;
1001 }
1002 } elseif ($action == 'addline' && GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines') !== '' && $usercancreate) {
1003 // Define margin
1004 $margin_rate = (GETPOST('marginforalllines') ? GETPOST('marginforalllines') : 0);
1005 foreach ($object->lines as $key => $line) {
1006 $subprice = price2num($line->pa_ht * (1 + $margin_rate / 100), 'MU');
1007 $prod = new Product($db);
1008 $prod->fetch($line->fk_product);
1009 if ($prod->price_min > $subprice) {
1010 $price_subprice = price($subprice, 0, $outlangs, 1, -1, -1, 'auto');
1011 $price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
1012 setEventMessages($prod->ref.' - '.$prod->label.' ('.$price_subprice.' < '.$price_price_min.' '.strtolower($langs->trans("MinPrice")).')'."\n", null, 'warnings');
1013 }
1014 // Manage $line->subprice and $line->multicurrency_subprice
1015 if ($line->subprice <> 0) {
1016 $multicurrency_subprice = (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1017 } else {
1018 $multicurrency_subprice = 0;
1019 }
1020 // Update DB
1021 $result = $object->updateline($line->id, $subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $multicurrency_subprice);
1022 $object->lines[$key] = $object->line;
1023 // Update $object with new margin info
1024 // $line->price = $subprice;
1025 // $line->marge_tx = $margin_rate;
1026 // $line->marque_tx = $margin_rate * $line->pa_ht / (float) $subprice;
1027 // $line->total_ht = $line->qty * (float) $subprice;
1028 // $line->total_tva = $line->tva_tx * $line->qty * (float) $subprice;
1029 // $line->total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice;
1030 // // Manage $line->subprice and $line->multicurrency_subprice
1031 // $line->multicurrency_total_ht = $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1032 // $line->multicurrency_total_tva = $line->tva_tx * $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1033 // $line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
1034 // // Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
1035 // $line->subprice = (float) $subprice;
1036 // $line->multicurrency_subprice = $multicurrency_subprice;
1037 }
1038 } elseif ($action == 'addline' && !GETPOST('submitforalllines', 'alpha') && !GETPOST('submitforallmargins', 'alpha') && $usercancreate) { // Add line
1039 // Set if we used free entry or predefined product
1040 $predef = '';
1041 $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
1042
1043 $price_ht = '';
1044 $price_ht_devise = '';
1045 $price_ttc = '';
1046 $price_ttc_devise = '';
1047
1048 // TODO Implement if (getDolGlobalInt('MAIN_UNIT_PRICE_WITH_TAX_IS_FOR_ALL_TAXES'))
1049
1050 if (GETPOST('price_ht') !== '') {
1051 $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
1052 }
1053 if (GETPOST('multicurrency_price_ht') !== '') {
1054 $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
1055 }
1056 if (GETPOST('price_ttc') !== '') {
1057 $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
1058 }
1059 if (GETPOST('multicurrency_price_ttc') !== '') {
1060 $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
1061 }
1062
1063 $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
1064 if ($prod_entry_mode == 'free') {
1065 $idprod = 0;
1066 } else {
1067 $idprod = GETPOSTINT('idprod');
1068
1069 if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
1070 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
1071 $error++;
1072 }
1073 }
1074
1075 $tva_tx = GETPOST('tva_tx', 'alpha');
1076
1077 $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
1078 $remise_percent = (GETPOSTISSET('remise_percent'.$predef) ? price2num(GETPOST('remise_percent'.$predef, 'alpha'), '', 2) : 0);
1079 if (empty($remise_percent)) {
1080 $remise_percent = 0;
1081 }
1082
1083 // Extrafields
1084 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1085 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
1086 // Unset extrafield
1087 if (is_array($extralabelsline)) {
1088 // Get extra fields
1089 foreach ($extralabelsline as $key => $value) {
1090 unset($_POST["options_".$key]);
1091 }
1092 }
1093
1094 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
1095 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1096 $error++;
1097 }
1098
1099 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && $price_ht === '' && $price_ht_devise === '' && $price_ttc === '' && $price_ttc_devise === '') { // Unit price can be 0 but not ''. Also price can be negative for proposal.
1100 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
1101 $error++;
1102 }
1103 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($product_desc)) {
1104 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
1105 $error++;
1106 }
1107
1108 if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
1109 if ($combinations = GETPOST('combinations', 'array')) {
1110 //Check if there is a product with the given combination
1111 $prodcomb = new ProductCombination($db);
1112
1113 if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
1114 $idprod = $res->fk_product_child;
1115 } else {
1116 setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
1117 $error++;
1118 }
1119 }
1120 }
1121
1122 $propal_qty_requirement = (getDolGlobalString('PROPAL_ENABLE_NEGATIVE_QTY') ? ($qty >= 0 || $qty <= 0) : $qty >= 0);
1123 if (!$error && $propal_qty_requirement && (!empty($product_desc) || (!empty($idprod) && $idprod > 0))) {
1124 $pu_ht = 0;
1125 $pu_ttc = 0;
1126 $pu_ht_devise = 0;
1127 $pu_ttc_devise = 0;
1128 $price_min = 0;
1129 $price_min_ttc = 0;
1130 $tva_npr = 0;
1131 $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
1132
1133 $db->begin();
1134
1135 // $tva_tx can be 'x.x (XXX)'
1136
1137 // Ecrase $pu par celui du produit
1138 // Ecrase $desc par celui du produit
1139 // Replaces $fk_unit with the product unit
1140 if (!empty($idprod) && $idprod > 0) {
1141 $prod = new Product($db);
1142 $prod->fetch($idprod);
1143
1144 $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
1145
1146 // Update if prices fields are defined
1147 /*$tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
1148 $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
1149 if (empty($tva_tx)) {
1150 $tva_npr = 0;
1151 }*/
1152
1153 // Price unique per product
1154 $pu_ht = $prod->price;
1155 $pu_ttc = $prod->price_ttc;
1156 $price_min = $prod->price_min;
1157 $price_min_ttc = $prod->price_min_ttc;
1158 $price_base_type = $prod->price_base_type;
1159
1160 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1161 // If price per customer
1162 require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
1163 $prodcustprice = new ProductCustomerPrice($db);
1164 $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $object->thirdparty->id);
1165
1166 // If a price per customer exist
1167 $pricebycustomerexist = false;
1168 $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1169 if ($result) {
1170 // If there is some prices specific to the customer
1171 if (count($prodcustprice->lines) > 0) {
1172 $pricebycustomerexist = true;
1173 $pu_ht = price($prodcustprice->lines[0]->price);
1174 $pu_ttc = price($prodcustprice->lines[0]->price_ttc);
1175 $price_min = price($prodcustprice->lines[0]->price_min);
1176 $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc);
1177 $price_base_type = $prodcustprice->lines[0]->price_base_type;
1178 /*$tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx);
1179 if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\‍(.*\‍)/', $tva_tx)) {
1180 $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')';
1181 }
1182 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
1183 if (empty($tva_tx)) {
1184 $tva_npr = 0;
1185 }*/
1186 }
1187 }
1188
1189 if (!$pricebycustomerexist && $object->thirdparty->price_level) { // If price per segment
1190 $pu_ht = $prod->multiprices[$object->thirdparty->price_level];
1191 $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
1192 $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
1193 $price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
1194 $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
1195 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
1196 if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
1197 $tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
1198 }
1199 if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
1200 $tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
1201 }
1202 }
1203 }
1204 } elseif (getDolGlobalString('PRODUIT_MULTIPRICES') && $object->thirdparty->price_level) { // If price per segment
1205 $pu_ht = $prod->multiprices[$object->thirdparty->price_level];
1206 $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
1207 $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
1208 $price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
1209 $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
1210 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
1211 if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
1212 $tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
1213 }
1214 if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
1215 $tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
1216 }
1217 }
1218 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
1219 // If price per customer
1220 require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
1221
1222 $prodcustprice = new ProductCustomerPrice($db);
1223
1224 $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $object->thirdparty->id);
1225
1226 $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1227 if ($result) {
1228 // If there is some prices specific to the customer
1229 if (count($prodcustprice->lines) > 0) {
1230 $pu_ht = price($prodcustprice->lines[0]->price);
1231 $pu_ttc = price($prodcustprice->lines[0]->price_ttc);
1232 $price_min = price($prodcustprice->lines[0]->price_min);
1233 $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc);
1234 $price_base_type = $prodcustprice->lines[0]->price_base_type;
1235 /*$tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx);
1236 if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\‍(.*\‍)/', $tva_tx)) {
1237 $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')';
1238 }
1239 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
1240 if (empty($tva_tx)) {
1241 $tva_npr = 0;
1242 }*/
1243 }
1244 }
1245 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY')) {
1246 // If price per quantity
1247 if ($prod->prices_by_qty[0]) { // yes, this product has some prices per quantity
1248 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1249 $pqp = GETPOSTINT('pbq');
1250
1251 // Search price into product_price_by_qty from $prod->id
1252 foreach ($prod->prices_by_qty_list[0] as $priceforthequantityarray) {
1253 if ($priceforthequantityarray['rowid'] != $pqp) {
1254 continue;
1255 }
1256 // We found the price
1257 if ($priceforthequantityarray['price_base_type'] == 'HT') {
1258 $pu_ht = $priceforthequantityarray['unitprice'];
1259 } else {
1260 $pu_ttc = $priceforthequantityarray['unitprice'];
1261 }
1262 // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1263 break;
1264 }
1265 }
1266 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
1267 // If price per quantity and customer
1268 if ($prod->prices_by_qty[$object->thirdparty->price_level]) { // yes, this product has some prices per quantity
1269 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1270 $pqp = GETPOSTINT('pbq');
1271
1272 // Search price into product_price_by_qty from $prod->id
1273 foreach ($prod->prices_by_qty_list[$object->thirdparty->price_level] as $priceforthequantityarray) {
1274 if ($priceforthequantityarray['rowid'] != $pqp) {
1275 continue;
1276 }
1277 // We found the price
1278 if ($priceforthequantityarray['price_base_type'] == 'HT') {
1279 $pu_ht = $priceforthequantityarray['unitprice'];
1280 } else {
1281 $pu_ttc = $priceforthequantityarray['unitprice'];
1282 }
1283 // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1284 break;
1285 }
1286 }
1287 }
1288
1289 $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
1290 $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', (string) $prod->tva_tx));
1291
1292 // Set unit price to use
1293 if (!empty($price_ht) || (string) $price_ht === '0') {
1294 $pu_ht = price2num($price_ht, 'MU');
1295 $pu_ttc = price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1296 } elseif (!empty($price_ht_devise) || (string) $price_ht_devise === '0') {
1297 $pu_ht_devise = price2num($price_ht_devise, 'MU');
1298 $pu_ht = '';
1299 $pu_ttc = '';
1300 } elseif (!empty($price_ttc) || (string) $price_ttc === '0') {
1301 $pu_ttc = price2num($price_ttc, 'MU');
1302 $pu_ht = price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1303 } elseif ($tmpvat != $tmpprodvat) {
1304 // Is this still used ?
1305 if ($price_base_type != 'HT') {
1306 $pu_ht = price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1307 } else {
1308 $pu_ttc = price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1309 }
1310 }
1311
1312 $desc = '';
1313
1314 // Define output language
1315 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1316 $outputlangs = $langs;
1317 $newlang = '';
1318 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1319 $newlang = GETPOST('lang_id', 'aZ09');
1320 }
1321 if (empty($newlang)) {
1322 $newlang = $object->thirdparty->default_lang;
1323 }
1324 if (!empty($newlang)) {
1325 $outputlangs = new Translate("", $conf);
1326 $outputlangs->setDefaultLang($newlang);
1327 }
1328
1329 $desc = (!empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description;
1330 } else {
1331 $desc = $prod->description;
1332 }
1333
1334 //If text set in desc is the same as product description (as now it's preloaded) we add it only one time
1335 if ($product_desc == $desc && getDolGlobalString('PRODUIT_AUTOFILL_DESC')) {
1336 $product_desc = '';
1337 }
1338
1339 if (!empty($product_desc) && getDolGlobalString('MAIN_NO_CONCAT_DESCRIPTION')) {
1340 $desc = $product_desc;
1341 } else {
1342 $desc = dol_concatdesc($desc, $product_desc, false, getDolGlobalString('MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION') ? true : false);
1343 }
1344
1345 // Add custom code and origin country into description
1346 if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
1347 $tmptxt = '(';
1348 // Define output language
1349 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1350 $outputlangs = $langs;
1351 $newlang = '';
1352 if (empty($newlang) && GETPOST('lang_id', 'alpha')) {
1353 $newlang = GETPOST('lang_id', 'alpha');
1354 }
1355 if (empty($newlang)) {
1356 $newlang = $object->thirdparty->default_lang;
1357 }
1358 if (!empty($newlang)) {
1359 $outputlangs = new Translate("", $conf);
1360 $outputlangs->setDefaultLang($newlang);
1361 $outputlangs->load('products');
1362 }
1363 if (!empty($prod->customcode)) {
1364 $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
1365 }
1366 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1367 $tmptxt .= ' - ';
1368 }
1369 if (!empty($prod->country_code)) {
1370 $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, '', $db, $outputlangs, 0);
1371 }
1372 } else {
1373 if (!empty($prod->customcode)) {
1374 $tmptxt .= $langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
1375 }
1376 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1377 $tmptxt .= ' - ';
1378 }
1379 if (!empty($prod->country_code)) {
1380 $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, '', $db, $langs, 0);
1381 }
1382 }
1383 $tmptxt .= ')';
1384 $desc = dol_concatdesc($desc, $tmptxt);
1385 }
1386
1387 $type = $prod->type;
1388 $fk_unit = $prod->fk_unit;
1389 } else {
1390 $pu_ht = price2num($price_ht, 'MU');
1391 $pu_ttc = price2num($price_ttc, 'MU');
1392 $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
1393 if (empty($tva_tx)) {
1394 $tva_npr = 0;
1395 }
1396 $tva_tx = str_replace('*', '', $tva_tx);
1397 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1398 $desc = $product_desc;
1399 $type = GETPOST('type');
1400 $fk_unit = GETPOST('units', 'alpha');
1401 $pu_ht_devise = price2num($price_ht_devise, 'MU');
1402 $pu_ttc_devise = price2num($price_ttc_devise, 'MU');
1403
1404 if ($pu_ttc && !$pu_ht) {
1405 $price_base_type = 'TTC';
1406 }
1407 }
1408
1409 $info_bits = 0;
1410 if ($tva_npr) {
1411 $info_bits |= 0x01;
1412 }
1413
1414 // Local Taxes
1415 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
1416 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
1417
1418 // Margin
1419 $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : '');
1420 $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we must keep this value
1421
1422 $date_start = dol_mktime(GETPOSTINT('date_start'.$predef.'hour'), GETPOSTINT('date_start'.$predef.'min'), GETPOSTINT('date_start'.$predef.'sec'), GETPOSTINT('date_start'.$predef.'month'), GETPOSTINT('date_start'.$predef.'day'), GETPOSTINT('date_start'.$predef.'year'));
1423 $date_end = dol_mktime(GETPOSTINT('date_end'.$predef.'hour'), GETPOSTINT('date_end'.$predef.'min'), GETPOSTINT('date_end'.$predef.'sec'), GETPOSTINT('date_end'.$predef.'month'), GETPOSTINT('date_end'.$predef.'day'), GETPOSTINT('date_end'.$predef.'year'));
1424
1425 // Prepare a price equivalent for minimum price check
1426 $pu_equivalent = $pu_ht;
1427 $pu_equivalent_ttc = $pu_ttc;
1428 $currency_tx = $object->multicurrency_tx;
1429
1430 // Check if we have a foreign currency
1431 // If so, we update the pu_equiv as the equivalent price in base currency
1432 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1433 $pu_equivalent = (float) $pu_ht_devise * (float) $currency_tx;
1434 }
1435 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1436 $pu_equivalent_ttc = (float) $pu_ttc_devise * (float) $currency_tx;
1437 }
1438
1439 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1440 /*
1441 if ($pu_equivalent) {
1442 $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
1443 $pu_equivalent_ttc = ...
1444 } else {
1445 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
1446 $pu_equivalent_ht = ...
1447 }
1448 */
1449
1450 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1451 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1452
1453 // Check price is not lower than minimum
1454 if ($usermustrespectpricemin) {
1455 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < price2num($price_min)) && $price_base_type == 'HT') {
1456 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1457 setEventMessages($mesg, null, 'errors');
1458 $error++;
1459 } elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1460 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1461 setEventMessages($mesg, null, 'errors');
1462 $error++;
1463 }
1464 }
1465
1466 if (!$error) {
1467 // Insert line
1468 $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, min($rank, count($object->lines) + 1), 0, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $date_start, $date_end, $array_options, $fk_unit, '', 0, $pu_ht_devise);
1469
1470 if ($result > 0) {
1471 $db->commit();
1472
1473 $ret = $object->fetch($id); // Reload to get new records
1474 if ($ret > 0) {
1475 $object->fetch_thirdparty();
1476 }
1477
1478 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1479 // Define output language
1480 $outputlangs = $langs;
1481 if (getDolGlobalInt('MAIN_MULTILANGS')) {
1482 $outputlangs = new Translate("", $conf);
1483 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1484 $outputlangs->setDefaultLang($newlang);
1485 }
1486 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1487 }
1488
1489 unset($_POST['prod_entry_mode']);
1490
1491 unset($_POST['qty']);
1492 unset($_POST['type']);
1493 unset($_POST['remise_percent']);
1494 unset($_POST['price_ht']);
1495 unset($_POST['multicurrency_price_ht']);
1496 unset($_POST['price_ttc']);
1497 unset($_POST['tva_tx']);
1498 unset($_POST['product_ref']);
1499 unset($_POST['product_label']);
1500 unset($_POST['product_desc']);
1501 unset($_POST['fournprice']);
1502 unset($_POST['buying_price']);
1503 unset($_POST['np_marginRate']);
1504 unset($_POST['np_markRate']);
1505 unset($_POST['dp_desc']);
1506 unset($_POST['idprod']);
1507 unset($_POST['units']);
1508
1509 unset($_POST['date_starthour']);
1510 unset($_POST['date_startmin']);
1511 unset($_POST['date_startsec']);
1512 unset($_POST['date_startday']);
1513 unset($_POST['date_startmonth']);
1514 unset($_POST['date_startyear']);
1515 unset($_POST['date_endhour']);
1516 unset($_POST['date_endmin']);
1517 unset($_POST['date_endsec']);
1518 unset($_POST['date_endday']);
1519 unset($_POST['date_endmonth']);
1520 unset($_POST['date_endyear']);
1521 } else {
1522 $db->rollback();
1523
1524 setEventMessages($object->error, $object->errors, 'errors');
1525 }
1526 }
1527 }
1528 } elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
1529 // Update a line within proposal
1530
1531 // Clean parameters
1532 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
1533
1534 // Define info_bits
1535 $info_bits = 0;
1536 if (preg_match('/\*/', GETPOST('tva_tx'))) {
1537 $info_bits |= 0x01;
1538 }
1539
1540 // Define vat_rate
1541 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
1542 $vat_rate = str_replace('*', '', $vat_rate);
1543 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
1544 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
1545 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
1546 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
1547
1548 // Add buying price
1549 $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
1550 $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we must keep this value
1551
1552 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
1553 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
1554
1555 $date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), GETPOSTINT('date_startsec'), GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
1556 $date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), GETPOSTINT('date_endsec'), GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
1557
1558 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1559 if (empty($remise_percent)) {
1560 $remise_percent = 0;
1561 }
1562
1563 // Prepare a price equivalent for minimum price check
1564 $pu_equivalent = $pu_ht;
1565 $pu_equivalent_ttc = $pu_ttc;
1566
1567 $currency_tx = $object->multicurrency_tx;
1568
1569 // Check if we have a foreign currency
1570 // If so, we update the pu_equiv as the equivalent price in base currency
1571 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1572 $pu_equivalent = (float) $pu_ht_devise * (float) $currency_tx;
1573 }
1574 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1575 $pu_equivalent_ttc = (float) $pu_ttc_devise * (float) $currency_tx;
1576 }
1577
1578 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1579 /*
1580 if ($pu_equivalent) {
1581 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
1582 $pu_equivalent_ttc = ...
1583 } else {
1584 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
1585 $pu_equivalent_ht = ...
1586 }
1587 */
1588
1589 // Extrafields
1590 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1591 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
1592 // Unset extrafield
1593 if (is_array($extralabelsline)) {
1594 // Get extra fields
1595 foreach ($extralabelsline as $key => $value) {
1596 unset($_POST["options_".$key]);
1597 }
1598 }
1599
1600 // Define special_code for special lines
1601 $special_code = GETPOSTINT('special_code');
1602 if (!GETPOST('qty')) {
1603 $special_code = 3;
1604 }
1605
1606 $pu = $pu_ht;
1607 $price_base_type = 'HT';
1608 if (empty($pu) && !empty($pu_ttc)) {
1609 $pu = $pu_ttc;
1610 $price_base_type = 'TTC';
1611 }
1612
1613 // Check minimum price
1614 $productid = GETPOSTINT('productid');
1615 if (!empty($productid)) {
1616 $product = new Product($db);
1617 $res = $product->fetch($productid);
1618
1619 $type = $product->type;
1620 $price_base_type = $product->price_base_type;
1621 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
1622
1623 $price_min = $product->price_min;
1624 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1625 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
1626 }
1627 $price_min_ttc = $product->price_min_ttc;
1628 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1629 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
1630 }
1631
1632 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1633 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1634
1635 // Check price is not lower than minimum
1636 if ($usermustrespectpricemin) {
1637 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
1638 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1639 setEventMessages($mesg, null, 'errors');
1640 $error++;
1641 $action = 'editline';
1642 } elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1643 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1644 setEventMessages($mesg, null, 'errors');
1645 $error++;
1646 $action = 'editline';
1647 }
1648 }
1649 } else {
1650 $type = GETPOST('type');
1651 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1652
1653 // Check parameters
1654 if (GETPOST('type') < 0) {
1655 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1656 $error++;
1657 }
1658 }
1659
1660 if (!$error) {
1661 $db->begin();
1662
1663 if (!$user->hasRight('margins', 'creer')) {
1664 foreach ($object->lines as &$line) {
1665 if ($line->id == GETPOSTINT('lineid')) {
1666 $fournprice = $line->fk_fournprice;
1667 $buyingprice = $line->pa_ht;
1668 break;
1669 }
1670 }
1671 }
1672
1673 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
1674
1675 $result = $object->updateline(GETPOSTINT('lineid'), $pu, $qty, $remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $description, $price_base_type, $info_bits, $special_code, GETPOST('fk_parent_line'), 0, $fournprice, $buyingprice, $label, $type, $date_start, $date_end, $array_options, GETPOST("units"), $pu_ht_devise);
1676
1677 if ($result >= 0) {
1678 $db->commit();
1679
1680 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1681 // Define output language
1682 $outputlangs = $langs;
1683 if (getDolGlobalInt('MAIN_MULTILANGS')) {
1684 $outputlangs = new Translate("", $conf);
1685 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1686 $outputlangs->setDefaultLang($newlang);
1687 }
1688 $ret = $object->fetch($id); // Reload to get new records
1689 if ($ret > 0) {
1690 $object->fetch_thirdparty();
1691 }
1692 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1693 }
1694
1695 unset($_POST['qty']);
1696 unset($_POST['type']);
1697 unset($_POST['productid']);
1698 unset($_POST['remise_percent']);
1699 unset($_POST['price_ht']);
1700 unset($_POST['multicurrency_price_ht']);
1701 unset($_POST['price_ttc']);
1702 unset($_POST['tva_tx']);
1703 unset($_POST['product_ref']);
1704 unset($_POST['product_label']);
1705 unset($_POST['product_desc']);
1706 unset($_POST['fournprice']);
1707 unset($_POST['buying_price']);
1708
1709 unset($_POST['date_starthour']);
1710 unset($_POST['date_startmin']);
1711 unset($_POST['date_startsec']);
1712 unset($_POST['date_startday']);
1713 unset($_POST['date_startmonth']);
1714 unset($_POST['date_startyear']);
1715 unset($_POST['date_endhour']);
1716 unset($_POST['date_endmin']);
1717 unset($_POST['date_endsec']);
1718 unset($_POST['date_endday']);
1719 unset($_POST['date_endmonth']);
1720 unset($_POST['date_endyear']);
1721 } else {
1722 $db->rollback();
1723
1724 setEventMessages($object->error, $object->errors, 'errors');
1725 }
1726 }
1727 } elseif ($action == 'updateline' && $usercancreate && GETPOST('cancel', 'alpha')) {
1728 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To re-display card in edit mode
1729 exit();
1730 } elseif ($action == 'classin' && $usercancreate) {
1731 // Set project
1732 $object->setProject(GETPOSTINT('projectid'));
1733 } elseif ($action == 'setavailability' && $usercancreate) {
1734 // Delivery time
1735 $result = $object->set_availability($user, GETPOSTINT('availability_id'));
1736 } elseif ($action == 'setdemandreason' && $usercancreate) {
1737 // Origin of the commercial proposal
1738 $result = $object->set_demand_reason($user, GETPOSTINT('demand_reason_id'));
1739 } elseif ($action == 'setconditions' && $usercancreate) {
1740 // Terms of payment
1741 $sql = "SELECT code ";
1742 $sql .= "FROM " . $db->prefix() . "c_payment_term";
1743 $sql .= " WHERE rowid = " . ((int) GETPOST('cond_reglement_id', 'int'));
1744 $result = $db->query($sql);
1745 if ($result) {
1746 $obj = $db->fetch_object($result);
1747 if ($obj->code == 'DEP30PCTDEL') {
1748 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'), GETPOSTFLOAT('cond_reglement_id_deposit_percent'));
1749 } else {
1750 $object->deposit_percent = 0;
1751 $object->update($user);
1752 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'), $object->deposit_percent);
1753 }
1754 }
1755 //} elseif ($action == 'setremisepercent' && $usercancreate) {
1756 // $result = $object->set_remise_percent($user, price2num(GETPOST('remise_percent'), '', 2));
1757 //} elseif ($action == 'setremiseabsolue' && $usercancreate) {
1758 // $result = $object->set_remise_absolue($user, price2num(GETPOST('remise_absolue'), 'MU', 2));
1759 } elseif ($action == 'setmode' && $usercancreate) {
1760 // Payment choice
1761 $result = $object->setPaymentMethods(GETPOSTINT('mode_reglement_id'));
1762 } elseif ($action == 'setmulticurrencycode' && $usercancreate) {
1763 // Multicurrency Code
1764 $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
1765 } elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
1766 // Multicurrency rate
1767 $result = $object->setMulticurrencyRate(price2num(GETPOST('multicurrency_tx')), GETPOSTINT('calculation_mode'));
1768 } elseif ($action == 'setbankaccount' && $usercancreate) {
1769 // bank account
1770 $result = $object->setBankAccount(GETPOSTINT('fk_account'));
1771 } elseif ($action == 'setshippingmethod' && $usercancreate) {
1772 // shipping method
1773 $result = $object->setShippingMethod(GETPOSTINT('shipping_method_id'));
1774 } elseif ($action == 'setwarehouse' && $usercancreate) {
1775 // warehouse
1776 $result = $object->setWarehouse(GETPOSTINT('warehouse_id'));
1777 } elseif ($action == 'update_extras' && $usercancreate) {
1778 $object->oldcopy = dol_clone($object, 2);
1779 $attribute_name = GETPOST('attribute', 'restricthtml');
1780
1781 // Fill array 'array_options' with data from update form
1782 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
1783 if ($ret < 0) {
1784 $error++;
1785 }
1786 if (!$error) {
1787 $result = $object->updateExtraField($attribute_name, 'PROPAL_MODIFY');
1788 if ($result < 0) {
1789 setEventMessages($object->error, $object->errors, 'errors');
1790 $error++;
1791 }
1792 }
1793 if ($error) {
1794 $action = 'edit_extras';
1795 }
1796 }
1797
1798 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
1799 if ($action == 'addcontact' && $usercancreate) {
1800 if ($object->id > 0) {
1801 $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
1802 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
1803 $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
1804 }
1805
1806 if ($result >= 0) {
1807 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1808 exit();
1809 } else {
1810 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1811 $langs->load("errors");
1812 setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
1813 } else {
1814 setEventMessages($object->error, $object->errors, 'errors');
1815 }
1816 }
1817 } elseif ($action == 'swapstatut' && $usercancreate) {
1818 // Toggle the status of a contact
1819 if ($object->fetch($id) > 0) {
1820 $result = $object->swapContactStatus(GETPOSTINT('ligne'));
1821 } else {
1822 dol_print_error($db);
1823 }
1824 } elseif ($action == 'deletecontact' && $usercancreate) {
1825 // Delete a contact
1826 $object->fetch($id);
1827 $result = $object->delete_contact($lineid);
1828
1829 if ($result >= 0) {
1830 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1831 exit();
1832 } else {
1833 dol_print_error($db);
1834 }
1835 }
1836 }
1837
1838 // Actions to build doc
1839 $upload_dir = !empty($conf->propal->multidir_output[$object->entity]) ? $conf->propal->multidir_output[$object->entity] : $conf->propal->dir_output;
1840 $permissiontoadd = $usercancreate;
1841 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
1842}
1843
1844
1845/*
1846 * View
1847 */
1848
1849$form = new Form($db);
1850$formfile = new FormFile($db);
1851$formpropal = new FormPropal($db);
1852$formmargin = new FormMargin($db);
1853$formproject = null;
1854if (isModEnabled('project')) {
1855 $formproject = new FormProjets($db);
1856}
1857
1858$title = $object->ref." - ".$langs->trans('Card');
1859if ($action == 'create') {
1860 $title = $langs->trans("NewPropal");
1861}
1862$help_url = 'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos|DE:Modul_Angebote';
1863
1864llxHeader('', $title, $help_url);
1865
1866$now = dol_now();
1867
1868// Add new proposal
1869if ($action == 'create') {
1870 $currency_code = $conf->currency;
1871
1872 print load_fiche_titre($langs->trans("NewProp"), '', 'propal');
1873
1874 $soc = new Societe($db);
1875 if ($socid > 0) {
1876 $res = $soc->fetch($socid);
1877 }
1878
1879 $currency_code = $conf->currency;
1880
1881 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
1882 $deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
1883 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
1884 $fk_account = GETPOSTINT('fk_account');
1885 $datepropal = (empty($datepropal) ? (!getDolGlobalString('MAIN_AUTOFILL_DATE_PROPOSAL') ? -1 : '') : $datepropal);
1886
1887 // Load objectsrc
1888 $objectsrc = null;
1889 if (!empty($origin) && !empty($originid)) {
1890 // Parse element/subelement (ex: project_task)
1891 $element = $subelement = $origin;
1892 $regs = array();
1893 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
1894 $element = $regs[1];
1895 $subelement = $regs[2];
1896 }
1897
1898 if ($element == 'project') {
1899 $projectid = $originid;
1900
1901 // Fetch project and thirdparty
1902 $project = new Project($db);
1903 $project->fetch($projectid);
1904 if ($project->socid > 0) {
1905 $soc = new Societe($db);
1906 $soc->fetch($project->socid);
1907 }
1908 } else {
1909 // For compatibility
1910 if ($element == 'order' || $element == 'commande') {
1911 $element = $subelement = 'commande';
1912 }
1913 if ($element == 'propal') {
1914 $element = 'comm/propal';
1915 $subelement = 'propal';
1916 }
1917 if ($element == 'contract') {
1918 $element = $subelement = 'contrat';
1919 }
1920 if ($element == 'shipping') {
1921 $element = $subelement = 'expedition';
1922 }
1923
1924 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
1925
1926 $classname = ucfirst($subelement);
1927 $objectsrc = new $classname($db);
1928 '@phan-var-force Commande|Propal|Contrat|Expedition $objectsrc'; // Can be other class, but CommonObject is too generic
1929 $objectsrc->fetch($originid);
1930 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
1931 $objectsrc->fetch_lines();
1932 }
1933 $objectsrc->fetch_thirdparty();
1934
1935 $projectid = (!empty($objectsrc->fk_project) ? $objectsrc->fk_project : 0);
1936 $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : '');
1937
1938 $soc = $objectsrc->thirdparty;
1939
1940 $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
1941 $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
1942 $warehouse_id = (!empty($objectsrc->warehouse_id) ? $objectsrc->warehouse_id : (!empty($soc->warehouse_id) ? $soc->warehouse_id : 0));
1943
1944 // Replicate extrafields
1945 $objectsrc->fetch_optionals();
1946 $object->array_options = $objectsrc->array_options;
1947
1948 if (isModEnabled("multicurrency")) {
1949 if (!empty($objectsrc->multicurrency_code)) {
1950 $currency_code = $objectsrc->multicurrency_code;
1951 }
1952 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
1953 $currency_tx = $objectsrc->multicurrency_tx;
1954 }
1955 }
1956 }
1957 }
1958
1959 // Load default values from thirdparty
1960 if (!empty($soc)) {
1961 $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
1962 $deposit_percent = empty($soc->deposit_percent) ? $deposit_percent : $soc->deposit_percent;
1963 $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
1964 $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
1965 $shipping_method_id = $soc->shipping_method_id;
1966 $warehouse_id = $soc->fk_warehouse;
1967 $remise_percent = $soc->remise_percent;
1968
1969 if (isModEnabled("multicurrency") && !empty($soc->multicurrency_code)) {
1970 $currency_code = $soc->multicurrency_code;
1971 }
1972 }
1973
1974 // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
1975 if (!GETPOST('changecompany')) {
1976 if (GETPOSTISSET('cond_reglement_id')) {
1977 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
1978 }
1979 if (GETPOSTISSET('deposit_percent')) {
1980 $deposit_percent = price2num(GETPOST('deposit_percent', 'alpha'));
1981 }
1982 if (GETPOSTISSET('mode_reglement_id')) {
1983 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
1984 }
1985 if (GETPOSTISSET('fk_account')) {
1986 $fk_account = GETPOSTINT('fk_account');
1987 }
1988 }
1989
1990 // Warehouse default if null
1991 if ($soc->fk_warehouse > 0) {
1992 $warehouse_id = $soc->fk_warehouse;
1993 }
1994 if (isModEnabled('stock') && empty($warehouse_id) && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER')) {
1995 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE')) {
1996 $warehouse_id = getDolGlobalString('MAIN_DEFAULT_WAREHOUSE');
1997 }
1998 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && !empty($user->fk_warehouse)) {
1999 $warehouse_id = $user->fk_warehouse;
2000 }
2001 }
2002
2003 print '<form name="addprop" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2004 print '<input type="hidden" name="token" value="'.newToken().'">';
2005 print '<input type="hidden" name="action" value="add">';
2006 print '<input type="hidden" name="changecompany" value="0">'; // will be set to 1 by javascript so we know post is done after a company change
2007 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2008 if ($origin != 'project' && $originid) {
2009 print '<input type="hidden" name="origin" value="'.$origin.'">';
2010 print '<input type="hidden" name="originid" value="'.$originid.'">';
2011 } elseif ($origin == 'project' && !empty($projectid)) {
2012 print '<input type="hidden" name="projectid" value="'.$projectid.'">';
2013 }
2014
2015 print dol_get_fiche_head();
2016
2017 // Call Hook tabContentCreateProposal
2018 $parameters = array();
2019 // Note that $action and $object may be modified by hook
2020 $reshook = $hookmanager->executeHooks('tabContentCreateProposal', $parameters, $object, $action);
2021 if (empty($reshook)) {
2022 print '<table class="border centpercent">';
2023
2024 // Reference
2025 print '<tr class="field_ref"><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td><td class="valuefieldcreate">'.$langs->trans("Draft").'</td></tr>';
2026
2027 // Ref customer
2028 print '<tr class="field_ref_client"><td class="titlefieldcreate">'.$langs->trans('RefCustomer').'</td><td class="valuefieldcreate">';
2029 print '<input type="text" name="ref_client" value="'.(!empty($ref_client) ? $ref_client : GETPOST('ref_client')).'"></td>';
2030 print '</tr>';
2031
2032 // Third party
2033 print '<tr class="field_socid">';
2034 print '<td class="titlefieldcreate fieldrequired">'.$langs->trans('Customer').'</td>';
2035 $shipping_method_id = 0;
2036 $warehouse_id = 0;
2037 if ($socid > 0) {
2038 print '<td class="valuefieldcreate">';
2039 print $soc->getNomUrl(1, 'customer');
2040 print '<input type="hidden" name="socid" value="'.$soc->id.'">';
2041 print '</td>';
2042 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2043 $shipping_method_id = $soc->shipping_method_id;
2044 }
2045 //$warehouse_id = $soc->warehouse_id;
2046 } else {
2047 print '<td class="valuefieldcreate">';
2048 $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
2049 print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company('', 'socid', $filter, 'SelectThirdParty', 1, 0, array(), 0, 'minwidth300 maxwidth500 widthcentpercentminusxx');
2050 // reload page to retrieve customer information
2051 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
2052 print '<script>
2053 $(document).ready(function() {
2054 $("#socid").change(function() {
2055 console.log("We have changed the company - Reload page");
2056 var socid = $(this).val();
2057 // reload page
2058 $("input[name=action]").val("create");
2059 $("input[name=changecompany]").val("1");
2060 $("form[name=addprop]").submit();
2061 });
2062 });
2063 </script>';
2064 }
2065 print ' <a href="'.DOL_URL_ROOT.'/societe/card.php?action=create&prospect=3&fournisseur=0&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create').'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddThirdParty").'"></span></a>';
2066 print '</td>';
2067 }
2068 print '</tr>'."\n";
2069
2070 if ($socid > 0) {
2071 // Contacts (ask contact only if thirdparty already defined).
2072 print '<tr class="field_contactid"><td class="titlefieldcreate">'.$langs->trans("DefaultContact").'</td><td class="valuefieldcreate">';
2073 print img_picto('', 'contact', 'class="pictofixedwidth"');
2074 //print $form->selectcontacts($soc->id, $contactid, 'contactid', 1, '', '', 0, 'minwidth300 widthcentpercentminusx');
2075 print $form->select_contact($soc->id, $contactid, 'contactid', 1, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
2076 print '</td></tr>';
2077
2078 // Third party discounts info line
2079 print '<tr class="field_discount_info"><td class="titlefieldcreate">'.$langs->trans('Discounts').'</td><td class="valuefieldcreate">';
2080
2081 $absolute_discount = $soc->getAvailableDiscounts();
2082
2083 $thirdparty = $soc;
2084 $discount_type = 0;
2085 $backtopage = $_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.urlencode((string) (GETPOST('origin'))).'&originid='.urlencode((string) (GETPOSTINT('originid')));
2086 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
2087 print '</td></tr>';
2088 }
2089
2090 $newdatepropal = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'), 'tzserver');
2091 // Date
2092 print '<tr class="field_addprop"><td class="titlefieldcreate fieldrequired">'.$langs->trans('DatePropal').'</td><td class="valuefieldcreate">';
2093 print img_picto('', 'action', 'class="pictofixedwidth"');
2094 print $form->selectDate($newdatepropal ? $newdatepropal : $datepropal, '', 0, 0, 0, "addprop", 1, 1);
2095 print '</td></tr>';
2096
2097 // Validaty duration
2098 print '<tr class="field_duree_validitee"><td class="titlefieldcreate fieldrequired">'.$langs->trans("ValidityDuration").'</td><td class="valuefieldcreate">'.img_picto('', 'clock', 'class="pictofixedwidth"').'<input name="duree_validite" class="width50" value="'.(GETPOSTISSET('duree_validite') ? GETPOST('duree_validite', 'alphanohtml') : getDolGlobalString('PROPALE_VALIDITY_DURATION')).'"> '.$langs->trans("days").'</td></tr>';
2099
2100 // Terms of payment
2101 print '<tr class="field_cond_reglement_id"><td class="nowrap">'.$langs->trans('PaymentConditionsShort').'</td><td>';
2102 print img_picto('', 'payment', 'class="pictofixedwidth"');
2103 // at last resort we take the payment term id which may be filled by default values set (if not getpostisset)
2104 print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', 1, 1, 0, '', $deposit_percent);
2105 print '</td></tr>';
2106
2107 // Mode of payment
2108 print '<tr class="field_mode_reglement_id"><td class="titlefieldcreate">'.$langs->trans('PaymentMode').'</td><td class="valuefieldcreate">';
2109 print img_picto('', 'bank', 'class="pictofixedwidth"');
2110 print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
2111 print '</td></tr>';
2112
2113 // Bank Account
2114 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
2115 print '<tr class="field_fk_account"><td class="titlefieldcreate">'.$langs->trans('BankAccount').'</td><td class="valuefieldcreate">';
2116 print img_picto('', 'bank_account', 'class="pictofixedwidth"').$form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
2117 print '</td></tr>';
2118 }
2119
2120 // Source / Channel - What trigger creation
2121 print '<tr class="field_demand_reason_id"><td class="titlefieldcreate">'.$langs->trans('Source').'</td><td class="valuefieldcreate">';
2122 print img_picto('', 'question', 'class="pictofixedwidth"');
2123 $form->selectInputReason((GETPOSTISSET('demand_reason_id') ? GETPOSTINT('demand_reason_id') : ''), 'demand_reason_id', "SRC_PROP", 1, 'maxwidth200 widthcentpercentminusx');
2124 print '</td></tr>';
2125
2126 // Shipping Method
2127 if (isModEnabled("shipping")) {
2128 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2129 $shipping_method_id = $soc->shipping_method_id;
2130 }
2131 print '<tr class="field_shipping_method_id"><td class="titlefieldcreate">'.$langs->trans('SendingMethod').'</td><td class="valuefieldcreate">';
2132 print img_picto('', 'dolly', 'class="pictofixedwidth"');
2133 $form->selectShippingMethod((GETPOSTISSET('shipping_method_id') ? GETPOSTINT('shipping_method_id') : $shipping_method_id), 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx');
2134 print '</td></tr>';
2135 }
2136
2137 $formproduct = null;
2138 // Warehouse
2139 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2140 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
2141 $formproduct = new FormProduct($db);
2142 print '<tr class="field_warehouse_id"><td class="titlefieldcreate">'.$langs->trans('Warehouse').'</td><td class="valuefieldcreate">';
2143 print img_picto('', 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx');
2144 print '</td></tr>';
2145 }
2146
2147 // Delivery delay
2148 print '<tr class="field_availability_id"><td class="titlefieldcreate">'.$langs->trans('AvailabilityPeriod');
2149 if (isModEnabled('order')) {
2150 print ' ('.$langs->trans('AfterOrder').')';
2151 }
2152 print '</td><td class="valuefieldcreate">';
2153 print img_picto('', 'clock', 'class="pictofixedwidth"');
2154 $form->selectAvailabilityDelay((GETPOSTISSET('availability_id') ? GETPOSTINT('availability_id') : ''), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx');
2155 print '</td></tr>';
2156
2157 // Delivery date (or manufacturing)
2158 print '<tr class="field_date_livraison"><td class="titlefieldcreate">'.$langs->trans("DeliveryDate").'</td>';
2159 print '<td class="valuefieldcreate">';
2160 print img_picto('', 'action', 'class="pictofixedwidth"');
2161 if (is_numeric(getDolGlobalString('DATE_LIVRAISON_WEEK_DELAY'))) { // If value set to 0 or a num, not empty
2162 $tmpdte = time() + (7 * getDolGlobalInt('DATE_LIVRAISON_WEEK_DELAY') * 24 * 60 * 60);
2163 $syear = date("Y", $tmpdte);
2164 $smonth = date("m", $tmpdte);
2165 $sday = date("d", $tmpdte);
2166 print $form->selectDate($syear."-".$smonth."-".$sday, 'date_livraison', 0, 0, 0, "addprop");
2167 } else {
2168 $tmp_date_delivery = GETPOST('date_delivery') ? : -1;
2169 print $form->selectDate($tmp_date_delivery, 'date_livraison', 0, 0, 0, "addprop", 1, 1);
2170 }
2171 print '</td></tr>';
2172
2173 // Project
2174 if (isModEnabled('project') && is_object($formproject)) {
2175 $langs->load("projects");
2176 print '<tr class="field_projectid">';
2177 print '<td class="titlefieldcreate">'.$langs->trans("Project").'</td><td class="valuefieldcreate">';
2178 print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects(($soc->id > 0 ? $soc->id : -1), $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500 widthcentpercentminusxx');
2179 print ' <a href="'.DOL_URL_ROOT.'/projet/card.php?socid='.$soc->id.'&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id).'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddProject").'"></span></a>';
2180 print '</td>';
2181 print '</tr>';
2182 }
2183
2184 // Incoterms
2185 if (isModEnabled('incoterm')) {
2186 print '<tr class="field_incoterm_id">';
2187 print '<td class="titlefieldcreate"><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $soc->label_incoterms, 1).'</label></td>';
2188 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2189 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
2190 print $form->select_incoterms((!empty($soc->fk_incoterms) ? $soc->fk_incoterms : ''), (!empty($soc->location_incoterms) ? $soc->location_incoterms : ''));
2191 print '</td></tr>';
2192 }
2193
2194 // Template to use by default
2195 print '<tr class="field_model">';
2196 print '<td class="titlefieldcreate">'.$langs->trans("DefaultModel").'</td>';
2197 print '<td class="valuefieldcreate">';
2198 print img_picto('', 'pdf', 'class="pictofixedwidth"');
2200 $preselected = (getDolGlobalString('PROPALE_ADDON_PDF_ODT_DEFAULT') ? $conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT : getDolGlobalString("PROPALE_ADDON_PDF"));
2201 print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
2202 print "</td></tr>";
2203
2204 // Multicurrency
2205 if (isModEnabled("multicurrency")) {
2206 print '<tr class="field_currency">';
2207 print '<td class="titlefieldcreate">'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
2208 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2209 print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0);
2210 print '</td></tr>';
2211 }
2212
2213 // Public note
2214 print '<tr class="field_note_public">';
2215 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePublic').'</td>';
2216 print '<td class="valuefieldcreate">';
2217 $note_public = $object->getDefaultCreateValueFor('note_public', (!empty($objectsrc) ? $objectsrc->note_public : (getDolGlobalString('PROPALE_ADDON_NOTE_PUBLIC_DEFAULT') ? $conf->global->PROPALE_ADDON_NOTE_PUBLIC_DEFAULT : null)), 'restricthtml');
2218 $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
2219 print $doleditor->Create(1);
2220
2221 // Private note
2222 if (empty($user->socid)) {
2223 print '<tr class="field_note_private">';
2224 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePrivate').'</td>';
2225 print '<td class="valuefieldcreate">';
2226 $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc)) ? $objectsrc->note_private : null));
2227 $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
2228 print $doleditor->Create(1);
2229 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
2230 print '</td></tr>';
2231 }
2232
2233 // Other attributes
2234 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
2235
2236 // Lines from source
2237 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2238 // TODO for compatibility
2239 if ($origin == 'contrat') {
2240 // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
2241 //$objectsrc->remise_absolue = $remise_absolue; // deprecated
2242 //$objectsrc->remise_percent = $remise_percent;
2243 $objectsrc->update_price(1, 'auto', 1);
2244 }
2245
2246 print "\n<!-- ".$classname." info -->";
2247 print "\n";
2248 print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
2249 print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
2250 print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
2251 print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
2252 print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
2253
2254 $newclassname = $classname;
2255 if ($newclassname == 'Propal') {
2256 $newclassname = 'CommercialProposal';
2257 } elseif ($newclassname == 'Commande') {
2258 $newclassname = 'Order';
2259 } elseif ($newclassname == 'Expedition') {
2260 $newclassname = 'Sending';
2261 } elseif ($newclassname == 'Fichinter') {
2262 $newclassname = 'Intervention';
2263 }
2264
2265 print '<tr><td>'.$langs->trans($newclassname).'</td><td>'.$objectsrc->getNomUrl(1).'</td></tr>';
2266 print '<tr><td>'.$langs->trans('AmountHT').'</td><td>'.price($objectsrc->total_ht, 0, $langs, 1, -1, -1, $conf->currency).'</td></tr>';
2267 print '<tr><td>'.$langs->trans('AmountVAT').'</td><td>'.price($objectsrc->total_tva, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2268 if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
2269 print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2270 }
2271
2272 if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
2273 print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2274 }
2275 print '<tr><td>'.$langs->trans('AmountTTC').'</td><td>'.price($objectsrc->total_ttc, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2276
2277 if (isModEnabled("multicurrency")) {
2278 print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td>'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
2279 print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td>'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
2280 print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td>'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
2281 }
2282 }
2283
2284 print "</table>\n";
2285
2286
2287 /*
2288 * Combobox for copy function
2289 */
2290
2291 if (!getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2292 print '<input type="hidden" name="createmode" value="empty">';
2293 }
2294
2295 if (getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2296 print '<br><table>';
2297
2298 // For backward compatibility
2299 print '<tr>';
2300 print '<td><input type="radio" name="createmode" value="copy"></td>';
2301 print '<td>'.$langs->trans("CopyPropalFrom").' </td>';
2302 print '<td>';
2303 $liste_propal = array();
2304 $liste_propal [0] = '';
2305
2306 $sql = "SELECT p.rowid as id, p.ref, s.nom";
2307 $sql .= " FROM ".MAIN_DB_PREFIX."propal p";
2308 $sql .= ", ".MAIN_DB_PREFIX."societe s";
2309 $sql .= " WHERE s.rowid = p.fk_soc";
2310 $sql .= " AND p.entity IN (".getEntity('propal').")";
2311 $sql .= " AND p.fk_statut <> 0";
2312 $sql .= " ORDER BY Id";
2313
2314 $resql = $db->query($sql);
2315 if ($resql) {
2316 $num = $db->num_rows($resql);
2317 $i = 0;
2318 while ($i < $num) {
2319 $row = $db->fetch_row($resql);
2320 $propalRefAndSocName = $row[1]." - ".$row[2];
2321 $liste_propal[$row[0]] = $propalRefAndSocName;
2322 $i++;
2323 }
2324 print $form->selectarray("copie_propal", $liste_propal, 0);
2325 } else {
2326 dol_print_error($db);
2327 }
2328 print '</td></tr>';
2329
2330 print '<tr><td class="tdtop"><input type="radio" name="createmode" value="empty" checked></td>';
2331 print '<td valign="top" colspan="2">'.$langs->trans("CreateEmptyPropal").'</td></tr>';
2332 print '</table>';
2333 }
2334 }
2335
2336 print dol_get_fiche_end();
2337
2338 $langs->load("bills");
2339
2340 print $form->buttonsSaveCancel("CreateDraft");
2341
2342 print "</form>";
2343
2344
2345 // Show origin lines
2346 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2347 print '<br>';
2348
2349 $title = $langs->trans('ProductsAndServices');
2350 print load_fiche_titre($title);
2351
2352 print '<div class="div-table-responsive-no-min">';
2353 print '<table class="noborder centpercent">';
2354
2355 $objectsrc->printOriginLinesList();
2356
2357 print '</table>';
2358 print '</div>';
2359 }
2360} elseif ($object->id > 0) {
2361 /*
2362 * Show object in view mode
2363 */
2364 $object->fetch_thirdparty();
2365 if ($object->thirdparty) {
2366 $soc = $object->thirdparty;
2367 } else {
2368 $soc = new Societe($db);
2369 }
2370
2372 print dol_get_fiche_head($head, 'comm', $langs->trans('Proposal'), -1, 'propal', 0, '', '', 0, '', 1);
2373
2374 $formconfirm = '';
2375
2376 // Clone confirmation
2377 if ($action == 'clone') {
2378 // Create an array for form
2379 $filter = '(s.client:IN:1,2,3)';
2380 $formquestion = array(
2381 // 'text' => $langs->trans("ConfirmClone"),
2382 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
2383 array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOSTINT('socid'), 'socid', $filter, '', 0, 0, array(), 0, 'maxwidth300')),
2384 array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0),
2385 array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0),
2386 );
2387 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY') && !empty($object->delivery_date)) {
2388 $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date);
2389 }
2390 // Incomplete payment. We ask if reason = discount or other
2391 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmClonePropal', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 250, 600);
2392 }
2393
2394 if ($action == 'closeas') {
2395 //Form to close proposal (signed or not)
2396 $formquestion = array();
2397 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2398 $formquestion[] = array('type' => 'select', 'name' => 'statut', 'label' => '<span class="fieldrequired">'.$langs->trans("CloseAs").'</span>', 'values' => array($object::STATUS_SIGNED => $object->LibStatut($object::STATUS_SIGNED), $object::STATUS_NOTSIGNED => $object->LibStatut($object::STATUS_NOTSIGNED)));
2399 }
2400 $formquestion[] = array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => ''); // Field to complete private note (not replace)
2401
2402 if (getDolGlobalInt('PROPOSAL_SUGGEST_DOWN_PAYMENT_INVOICE_CREATION')) {
2403 // This is a hidden option:
2404 // Suggestion to create invoice during proposal signature is not enabled by default.
2405 // Such choice should be managed by the workflow module and trigger. This option generates conflicts with some setup.
2406 // It may also break step of creating an order when invoicing must be done from orders and not from proposal
2407 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
2408
2409 if (!empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')) {
2410 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
2411
2412 $object->fetchObjectLinked();
2413
2414 $eligibleForDepositGeneration = true;
2415
2416 if (array_key_exists('facture', $object->linkedObjects)) {
2417 foreach ($object->linkedObjects['facture'] as $invoice) {
2418 '@phan-var-force Facture $invoice';
2419 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2420 $eligibleForDepositGeneration = false;
2421 break;
2422 }
2423 }
2424 }
2425
2426 if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) {
2427 foreach ($object->linkedObjects['commande'] as $order) {
2428 $order->fetchObjectLinked();
2429
2430 if (array_key_exists('facture', $order->linkedObjects)) {
2431 foreach ($order->linkedObjects['facture'] as $invoice) {
2432 '@phan-var-force Facture $invoice';
2433 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2434 $eligibleForDepositGeneration = false;
2435 break 2;
2436 }
2437 }
2438 }
2439 }
2440 }
2441
2442
2443 if ($eligibleForDepositGeneration) {
2444 $formquestion[] = array(
2445 'type' => 'checkbox',
2446 'tdclass' => 'showonlyifsigned',
2447 'name' => 'generate_deposit',
2448 'morecss' => 'margintoponly marginbottomonly',
2449 'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('DepositGenerationPermittedByThePaymentTermsSelected'))
2450 );
2451
2452 $formquestion[] = array(
2453 'type' => 'date',
2454 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2455 'name' => 'datef',
2456 'label' => $langs->trans('DateInvoice'),
2457 'value' => dol_now(),
2458 'datenow' => true
2459 );
2460
2461 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
2462 $formquestion[] = array(
2463 'type' => 'date',
2464 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2465 'name' => 'date_pointoftax',
2466 'label' => $langs->trans('DatePointOfTax'),
2467 'value' => dol_now(),
2468 'datenow' => true
2469 );
2470 }
2471
2472 $paymentTermsSelect = $form->getSelectConditionsPaiements(0, 'cond_reglement_id', -1, 0, 1, 'minwidth200');
2473
2474 $formquestion[] = array(
2475 'type' => 'other',
2476 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2477 'name' => 'cond_reglement_id',
2478 'label' => $langs->trans('PaymentTerm'),
2479 'value' => $paymentTermsSelect
2480 );
2481
2482 $formquestion[] = array(
2483 'type' => 'checkbox',
2484 'tdclass' => 'showonlyifgeneratedeposit',
2485 'name' => 'validate_generated_deposit',
2486 'morecss' => 'margintoponly marginbottomonly',
2487 'label' => $langs->trans('ValidateGeneratedDeposit')
2488 );
2489
2490 $formquestion[] = array(
2491 'type' => 'onecolumn',
2492 'value' => '
2493 <script>
2494 let signedValue = ' . $object::STATUS_SIGNED . ';
2495
2496 $(document).ready(function() {
2497 $("[name=generate_deposit]").change(function () {
2498 let $self = $(this);
2499 let $target = $(".showonlyifgeneratedeposit").parent(".tagtr");
2500
2501 if (! $self.parents(".tagtr").is(":hidden") && $self.is(":checked")) {
2502 $target.show();
2503 } else {
2504 $target.hide();
2505 }
2506
2507 return true;
2508 });
2509
2510 $("#statut").change(function() {
2511 let $target = $(".showonlyifsigned").parent(".tagtr");
2512
2513 if ($(this).val() == signedValue) {
2514 $target.show();
2515 } else {
2516 $target.hide();
2517 }
2518
2519 $("[name=generate_deposit]").trigger("change");
2520
2521 return true;
2522 });
2523
2524 $("#statut").trigger("change");
2525 });
2526 </script>
2527 '
2528 );
2529 }
2530 }
2531 }
2532
2533 if (isModEnabled('notification')) {
2534 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2535 $notify = new Notify($db);
2536 $formquestion = array_merge($formquestion, array(
2537 array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)),
2538 ));
2539 }
2540
2541 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2542 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetAcceptedRefused'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2543 } else {
2544 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?statut=3&id=' . $object->id, $langs->trans('Close'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2545 }
2546 } elseif ($action == 'cancel') {
2547 // Confirm cancel
2548 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("CancelPropal"), $langs->trans('ConfirmCancelPropal', $object->ref), 'confirm_cancel', '', 0, 1);
2549 } elseif ($action == 'delete') {
2550 // Confirm delete
2551 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp', $object->ref), 'confirm_delete', '', 0, 1);
2552 } elseif ($action == 'reopen') {
2553 // Confirm reopen
2554 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp', $object->ref), 'confirm_reopen', '', 0, 1);
2555 } elseif ($action == 'ask_deleteline') {
2556 // Confirmation delete product/service line
2557 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
2558 } elseif ($action == 'validate') {
2559 // Confirm validate proposal
2560 $error = 0;
2561
2562 // We verify whether the object is provisionally numbering
2563 $ref = substr($object->ref, 1, 4);
2564 if ($ref == 'PROV' || $ref == '') {
2565 $numref = $object->getNextNumRef($soc);
2566 if (empty($numref)) {
2567 $error++;
2568 setEventMessages($object->error, $object->errors, 'errors');
2569 }
2570 } else {
2571 $numref = $object->ref;
2572 }
2573
2574 $text = $langs->trans('ConfirmValidateProp', $numref);
2575 if (isModEnabled('notification')) {
2576 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2577 $notify = new Notify($db);
2578 $text .= '<br>';
2579 $text .= $notify->confirmMessage('PROPAL_VALIDATE', $object->socid, $object);
2580 }
2581
2582 // mandatoryPeriod
2583 $nbMandated = 0;
2584 foreach ($object->lines as $line) {
2585 $res = $line->fetch_product();
2586 if ($res > 0) {
2587 if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
2588 $nbMandated++;
2589 break;
2590 }
2591 }
2592 }
2593 if ($nbMandated > 0) {
2594 if (getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
2595 setEventMessages($langs->trans("mandatoryPeriodNeedTobeSetMsgValidate"), null, 'errors');
2596 $error++;
2597 } else {
2598 $text .= '<div><span class="clearboth nowraponall warning">'.img_warning().$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
2599 }
2600 }
2601
2602 if (!$error) {
2603 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateProp'), $text, 'confirm_validate', '', 0, 1, 240);
2604 }
2605 }
2606
2607 // Call Hook formConfirm
2608 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
2609 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2610 if (empty($reshook)) {
2611 $formconfirm .= $hookmanager->resPrint;
2612 } elseif ($reshook > 0) {
2613 $formconfirm = $hookmanager->resPrint;
2614 }
2615
2616 // Print form confirm
2617 print $formconfirm;
2618
2619
2620 // Proposal card
2621
2622 $linkback = '<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
2623
2624 $morehtmlref = '<div class="refidno">';
2625 // Ref customer
2626 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
2627 $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1);
2628 // Thirdparty
2629 $morehtmlref .= '<br>'.$soc->getNomUrl(1, 'customer');
2630 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $soc->id > 0) {
2631 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?socid='.$soc->id.'&search_societe='.urlencode($soc->name).'">'.$langs->trans("OtherProposals").'</a>)';
2632 }
2633 // Project
2634 if (isModEnabled('project')) {
2635 $langs->load("projects");
2636 $morehtmlref .= '<br>';
2637 if ($usercancreate) {
2638 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2639 if ($action != 'classify') {
2640 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
2641 }
2642 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
2643 } else {
2644 if (!empty($object->fk_project)) {
2645 $proj = new Project($db);
2646 $proj->fetch($object->fk_project);
2647 $morehtmlref .= $proj->getNomUrl(1);
2648 if ($proj->title) {
2649 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
2650 }
2651 }
2652 }
2653 }
2654 $morehtmlref .= '</div>';
2655
2656
2657 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
2658
2659 // Call Hook tabContentViewProposal
2660 $parameters = array();
2661 // Note that $action and $object may be modified by hook
2662 $reshook = $hookmanager->executeHooks('tabContentViewProposal', $parameters, $object, $action);
2663 if (empty($reshook)) {
2664 print '<div class="fichecenter">';
2665 print '<div class="fichehalfleft">';
2666 print '<div class="underbanner clearboth"></div>';
2667
2668 print '<table class="border tableforfield centpercent">';
2669
2670 // Link for thirdparty discounts
2671 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
2672 $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
2673 $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
2674 } else {
2675 $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
2676 $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
2677 }
2678
2679 print '<tr><td class="titlefieldmax45">'.$langs->trans('Discounts').'</td><td>';
2680
2681 $absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount);
2682 $absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote);
2683 $absolute_discount = price2num($absolute_discount, 'MT');
2684 $absolute_creditnote = price2num($absolute_creditnote, 'MT');
2685
2686 $caneditfield = ($object->status != Propal::STATUS_SIGNED && $object->status != Propal::STATUS_BILLED);
2687
2688 $thirdparty = $soc;
2689 $discount_type = 0;
2690 $backtopage = $_SERVER["PHP_SELF"].'?id='.$object->id;
2691 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
2692
2693 print '</td></tr>';
2694
2695 // Date of proposal
2696 print '<tr>';
2697 print '<td>';
2698 // print '<table class="nobordernopadding" width="100%"><tr><td>';
2699 // print $langs->trans('DatePropal');
2700 // print '</td>';
2701 // if ($action != 'editdate' && $usercancreate && $caneditfield) {
2702 // print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
2703 // }
2704
2705 // print '</tr></table>';
2706 $editenable = $usercancreate && $caneditfield && $object->status == Propal::STATUS_DRAFT;
2707 print $form->editfieldkey("DatePropal", 'date', '', $object, $editenable);
2708 print '</td><td class="valuefield">';
2709 if ($action == 'editdate' && $usercancreate && $caneditfield) {
2710 print '<form name="editdate" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2711 print '<input type="hidden" name="token" value="'.newToken().'">';
2712 print '<input type="hidden" name="action" value="setdate">';
2713 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2714 print $form->selectDate($object->date, 're', 0, 0, 0, "editdate");
2715 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2716 print '</form>';
2717 } else {
2718 if ($object->date) {
2719 print dol_print_date($object->date, 'day');
2720 } else {
2721 print '&nbsp;';
2722 }
2723 }
2724 print '</td>';
2725
2726 // Date end proposal
2727 print '<tr>';
2728 print '<td>';
2729 print '<table class="nobordernopadding centpercent"><tr><td>';
2730 print $langs->trans('DateEndPropal');
2731 print '</td>';
2732 if ($action != 'editecheance' && $usercancreate && $caneditfield) {
2733 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editecheance&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetConditions'), 1).'</a></td>';
2734 }
2735 print '</tr></table>';
2736 print '</td><td class="valuefield">';
2737 if ($action == 'editecheance' && $usercancreate && $caneditfield) {
2738 print '<form name="editecheance" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2739 print '<input type="hidden" name="token" value="'.newToken().'">';
2740 print '<input type="hidden" name="action" value="setecheance">';
2741 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2742 print $form->selectDate($object->fin_validite, 'ech', 0, 0, 0, "editecheance");
2743 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2744 print '</form>';
2745 } else {
2746 if (!empty($object->fin_validite)) {
2747 print dol_print_date($object->fin_validite, 'day');
2748 if ($object->status == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) {
2749 print img_warning($langs->trans("Late"));
2750 }
2751 } else {
2752 print '&nbsp;';
2753 }
2754 }
2755 print '</td>';
2756 print '</tr>';
2757
2758 // Payment term
2759 print '<tr><td>';
2760 print '<table class="nobordernopadding centpercent"><tr><td>';
2761 print $langs->trans('PaymentConditionsShort');
2762 print '</td>';
2763 if ($action != 'editconditions' && $usercancreate && $caneditfield) {
2764 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editconditions&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetConditions'), 1).'</a></td>';
2765 }
2766 print '</tr></table>';
2767 print '</td><td class="valuefield">';
2768 if ($action == 'editconditions' && $usercancreate && $caneditfield) {
2769 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 0, '', 1, $object->deposit_percent);
2770 } else {
2771 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 0, '', 1, $object->deposit_percent);
2772 }
2773 print '</td>';
2774 print '</tr>';
2775
2776 // Payment mode
2777 print '<tr class="field_mode_reglement_id">';
2778 print '<td>';
2779 print '<table class="nobordernopadding centpercent"><tr><td>';
2780 print $langs->trans('PaymentMode');
2781 print '</td>';
2782 if ($action != 'editmode' && $usercancreate && $caneditfield) {
2783 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmode&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetMode'), 1).'</a></td>';
2784 }
2785 print '</tr></table>';
2786 print '</td><td class="valuefieldcreate">';
2787 if ($action == 'editmode' && $usercancreate && $caneditfield) {
2788 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
2789 } else {
2790 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'none');
2791 }
2792 print '</td></tr>';
2793
2794 // Delivery date
2795 $langs->load('deliveries');
2796 print '<tr><td>';
2797 print $form->editfieldkey($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2798 print '</td><td class="valuefieldedit">';
2799 print $form->editfieldval($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2800 print '</td>';
2801 print '</tr>';
2802
2803 // Delivery delay
2804 print '<tr class="fielddeliverydelay"><td>';
2805 print '<table class="nobordernopadding centpercent"><tr><td>';
2806 if (isModEnabled('order')) {
2807 print $form->textwithpicto($langs->trans('AvailabilityPeriod'), $langs->trans('AvailabilityPeriod').' ('.$langs->trans('AfterOrder').')');
2808 } else {
2809 print $langs->trans('AvailabilityPeriod');
2810 }
2811 print '</td>';
2812 if ($action != 'editavailability' && $usercancreate && $caneditfield) {
2813 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editavailability&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetAvailability'), 1).'</a></td>';
2814 }
2815 print '</tr></table>';
2816 print '</td><td class="valuefield">';
2817 if ($action == 'editavailability' && $usercancreate && $caneditfield) {
2818 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'availability_id', 1);
2819 } else {
2820 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'none', 1);
2821 }
2822
2823 print '</td>';
2824 print '</tr>';
2825
2826 // Shipping Method
2827 if (isModEnabled("shipping")) {
2828 print '<tr><td>';
2829 print '<table class="nobordernopadding centpercent"><tr><td>';
2830 print $langs->trans('SendingMethod');
2831 print '</td>';
2832 if ($action != 'editshippingmethod' && $usercancreate && $caneditfield) {
2833 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editshippingmethod&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetShippingMode'), 1).'</a></td>';
2834 }
2835 print '</tr></table>';
2836 print '</td><td class="valuefield">';
2837 if ($action == 'editshippingmethod' && $usercancreate && $caneditfield) {
2838 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1);
2839 } else {
2840 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none');
2841 }
2842 print '</td>';
2843 print '</tr>';
2844 }
2845
2846 // Warehouse
2847 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2848 $langs->load('stocks');
2849 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
2850 $formproduct = new FormProduct($db);
2851 print '<tr class="field_warehouse_id"><td>';
2852 $editenable = $usercancreate;
2853 print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable);
2854 print '</td><td class="valuefieldcreate">';
2855 if ($action == 'editwarehouse') {
2856 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1);
2857 } else {
2858 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'none');
2859 }
2860 print '</td>';
2861 print '</tr>';
2862 }
2863
2864 // Origin of demand
2865 print '<tr><td>';
2866 print '<table class="nobordernopadding centpercent"><tr><td>';
2867 print $langs->trans('Source');
2868 print '</td>';
2869 if ($action != 'editdemandreason' && $usercancreate) {
2870 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdemandreason&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetDemandReason'), 1).'</a></td>';
2871 }
2872 print '</tr></table>';
2873 print '</td><td class="valuefield">';
2874 if ($action == 'editdemandreason' && $usercancreate) {
2875 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'demand_reason_id', 1);
2876 } else {
2877 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'none');
2878 }
2879 print '</td>';
2880 print '</tr>';
2881
2882 if ($soc->outstanding_limit) {
2883 // Outstanding Bill
2884 print '<tr><td>';
2885 print $langs->trans('OutstandingBill');
2886 print '</td><td class="valuefield">';
2887 $arrayoutstandingbills = $soc->getOutstandingBills();
2888 print($arrayoutstandingbills['opened'] > $soc->outstanding_limit ? img_warning() : '');
2889 print price($arrayoutstandingbills['opened']).' / ';
2890 print price($soc->outstanding_limit, 0, $langs, 1, - 1, - 1, $conf->currency);
2891 print '</td>';
2892 print '</tr>';
2893 }
2894
2895 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
2896 // Bank Account
2897 print '<tr><td>';
2898 print '<table width="100%" class="nobordernopadding"><tr><td>';
2899 print $langs->trans('BankAccount');
2900 print '</td>';
2901 if ($action != 'editbankaccount' && $usercancreate) {
2902 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editbankaccount&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetBankAccount'), 1).'</a></td>';
2903 }
2904 print '</tr></table>';
2905 print '</td><td class="valuefield">';
2906 if ($action == 'editbankaccount') {
2907 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1);
2908 } else {
2909 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none');
2910 }
2911 print '</td>';
2912 print '</tr>';
2913 }
2914
2915 if (!getDolGlobalString('PROPOSAL_HIDE_CALCULATED_WEIGHT_VOLUME')) {
2916 $tmparray = $object->getTotalWeightVolume();
2917 $totalWeight = isset($tmparray['weight']) ? $tmparray['weight'] : 0;
2918 $totalVolume = isset($tmparray['volume']) ? $tmparray['volume'] : 0;
2919 if ($totalWeight) {
2920 print '<tr><td>'.$langs->trans("CalculatedWeight").'</td>';
2921 print '<td class="valuefield">';
2922 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 'no'), 1);
2923 print '</td></tr>';
2924 }
2925 if ($totalVolume) {
2926 print '<tr><td>'.$langs->trans("CalculatedVolume").'</td>';
2927 print '<td class="valuefield">';
2928 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'), 1);
2929 print '</td></tr>';
2930 }
2931 }
2932
2933 // Incoterms
2934 if (isModEnabled('incoterm')) {
2935 print '<tr><td>';
2936 print '<table width="100%" class="nobordernopadding"><tr><td>';
2937 print $langs->trans('IncotermLabel');
2938 print '<td><td class="right">';
2939 if ($action != 'editincoterm' && $usercancreate && $caneditfield) {
2940 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/comm/propal/card.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
2941 } else {
2942 print '&nbsp;';
2943 }
2944 print '</td></tr></table>';
2945 print '</td>';
2946 print '<td class="valuefield">';
2947 if ($action == 'editincoterm' && $usercancreate && $caneditfield) {
2948 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
2949 } else {
2950 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
2951 }
2952 print '</td></tr>';
2953 }
2954
2955 // Other attributes
2956 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2957
2958 print '</table>';
2959
2960 print '</div>';
2961 print '<div class="fichehalfright">';
2962 print '<div class="underbanner clearboth"></div>';
2963
2964 print '<table class="border tableforfield centpercent">';
2965
2966 include DOL_DOCUMENT_ROOT.'/core/tpl/object_currency_amount.tpl.php';
2967
2968 print '<tr>';
2969 print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
2970 print '<td class="nowrap amountcard right">' . price($object->total_ht, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
2971 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2972 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ht, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2973 }
2974 print '</tr>';
2975
2976 print '<tr>';
2977 print '<td>' . $langs->trans('AmountVAT') . '</td>';
2978 print '<td class="nowrap amountcard right">' . price($object->total_tva, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
2979 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2980 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_tva, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2981 }
2982 print '</tr>';
2983
2984 if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
2985 print '<tr>';
2986 print '<td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
2987 print '<td class="nowrap amountcard right">' . price($object->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
2988 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2989 $object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
2990
2991 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
2992 }
2993 print '</tr>';
2994 }
2995
2996 if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
2997 print '<tr>';
2998 print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
2999 print '<td class="nowrap amountcard right">' . price($object->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3000 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3001 $object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
3002
3003 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3004 }
3005 print '</tr>';
3006 }
3007
3008 print '<tr>';
3009 print '<td>' . $langs->trans('AmountTTC') . '</td>';
3010 print '<td class="nowrap amountcard right">' . price($object->total_ttc, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3011 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3012 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ttc, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3013 }
3014 print '</tr>';
3015
3016 print '</table>';
3017
3018 // Margin Infos
3019 if (isModEnabled('margin')) {
3020 $formmargin->displayMarginInfos($object);
3021 }
3022
3023 print '</div>';
3024 print '</div>';
3025
3026 print '<div class="clearboth"></div><br>';
3027
3028 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
3029 $blocname = 'contacts';
3030 $title = $langs->trans('ContactsAddresses');
3031 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
3032 }
3033
3034 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
3035 $blocname = 'notes';
3036 $title = $langs->trans('Notes');
3037 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
3038 }
3039
3040 /*
3041 * Lines
3042 */
3043
3044 // Get object lines
3045 $result = $object->getLinesArray();
3046
3047 // Add products/services form
3048 //$forceall = 1;
3049 global $inputalsopricewithtax;
3050 $inputalsopricewithtax = 1;
3051
3052 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
3053 <input type="hidden" name="token" value="' . newToken().'">
3054 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
3055 <input type="hidden" name="mode" value="">
3056 <input type="hidden" name="page_y" value="">
3057 <input type="hidden" name="backtopage" value="'.$backtopage.'">
3058 <input type="hidden" name="id" value="' . $object->id.'">
3059 ';
3060
3061 if (!empty($conf->use_javascript_ajax) && $object->status == Propal::STATUS_DRAFT) {
3062 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
3063 }
3064
3065 print '<div class="div-table-responsive-no-min">';
3066 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3067 print '<table id="tablelines" class="noborder noshadow centpercent">';
3068 }
3069
3070 if (!empty($object->lines)) {
3071 $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 1);
3072 }
3073
3074 // Form to add new line
3075 if ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines') {
3076 if ($action != 'editline') {
3077 $parameters = array();
3078 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3079 if ($reshook < 0) {
3080 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3081 }
3082 if (empty($reshook)) {
3083 $object->formAddObjectLine(1, $mysoc, $soc);
3084 }
3085 } else {
3086 $parameters = array();
3087 $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3088 }
3089 }
3090
3091 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3092 print '</table>';
3093 }
3094 print '</div>';
3095
3096 print "</form>\n";
3097 }
3098
3099 print dol_get_fiche_end();
3100
3101
3102 /*
3103 * Button Actions
3104 */
3105
3106 if ($action != 'presend') {
3107 $numlines = count($object->lines);
3108 print '<div class="tabsAction">';
3109
3110 $parameters = array();
3111 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
3112 // modified by hook
3113 if (empty($reshook)) {
3114 if ($action != 'editline') {
3115 // Validate
3116 if (($object->status == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0)
3117 || ($object->status == Propal::STATUS_DRAFT && getDolGlobalString('PROPAL_ENABLE_NEGATIVE') && count($object->lines) > 0)) {
3118 if ($usercanvalidate) {
3119 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=validate&token='.newToken().'">'.(!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE') ? $langs->trans('Validate') : $langs->trans('ValidateAndSign')).'</a>';
3120 } else {
3121 print '<a class="butActionRefused classfortooltip" href="#">'.$langs->trans('Validate').'</a>';
3122 }
3123 }
3124 // Create event
3125 /*if (isModEnabled('agenda') && !empty($conf->global->MAIN_ADD_EVENT_ON_ELEMENT_CARD)) // Add hidden condition because this is not a "workflow" action so should appears somewhere else on page.
3126 {
3127 print '<a class="butAction" href="' . DOL_URL_ROOT . '/comm/action/card.php?action=create&amp;origin=' . $object->element . '&amp;originid=' . $object->id . '&amp;socid=' . $object->socid . '">' . $langs->trans("AddAction") . '</a></div>';
3128 }*/
3129 // Edit
3130 if ($object->status == Propal::STATUS_VALIDATED && $usercancreate) {
3131 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=modif&token='.newToken().'">'.$langs->trans('Modify').'</a>';
3132 }
3133
3134 // ReOpen
3135 if (((getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && $object->status == Propal::STATUS_NOTSIGNED) || (!getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && ($object->status == Propal::STATUS_SIGNED || $object->status == Propal::STATUS_NOTSIGNED || $object->status == Propal::STATUS_BILLED || $object->status == Propal::STATUS_CANCELED))) && $usercanclose) {
3136 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#reopen').'"';
3137 print '>'.$langs->trans('ReOpen').'</a>';
3138 }
3139
3140 // Send
3141 if (empty($user->socid)) {
3142 if ($object->status == Propal::STATUS_VALIDATED || $object->status == Propal::STATUS_SIGNED || getDolGlobalString('PROPOSAL_SENDBYEMAIL_FOR_ALL_STATUS')) {
3143 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '', $usercansend);
3144 }
3145 }
3146
3147 $arrayforbutaction = array();
3148
3149 // Create a sale order
3150 $arrayforbutaction[] = array(
3151 'lang' => 'orders',
3152 'enabled' => (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED),
3153 'perm' => $usercancreateorder,
3154 'label' => 'AddOrder',
3155 'url' => '/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3156 );
3157 /*if (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED) {
3158 if ($usercancreateorder) {
3159 print '<a class="butAction" href="'.DOL_URL_ROOT.'/commande/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddOrder").'</a>';
3160 }
3161 }*/
3162
3163 // Create a purchase order
3164 if (getDolGlobalString('WORKFLOW_CAN_CREATE_PURCHASE_ORDER_FROM_PROPOSAL')) {
3165 $arrayforbutaction[] = array(
3166 'lang' => 'orders',
3167 'enabled' => ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")),
3168 'perm' => $usercancreatepurchaseorder,
3169 'label' => 'AddPurchaseOrder',
3170 'url' => '/fourn/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3171 );
3172 /*if ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")) {
3173 if ($usercancreatepurchaseorder) {
3174 print '<a class="butAction" href="'.DOL_URL_ROOT.'/fourn/commande/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddPurchaseOrder").'</a>';
3175 }
3176 }*/
3177 }
3178
3179 // Create an intervention
3180 $arrayforbutaction[] = array(
3181 'lang' => 'interventions',
3182 'enabled' => (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED),
3183 'perm' => $usercancreateintervention,
3184 'label' => 'AddIntervention',
3185 'url' => '/fichinter/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3186 );
3187 /*if (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED) {
3188 if ($usercancreateintervention) {
3189 $langs->load("interventions");
3190 print '<a class="butAction" href="'.DOL_URL_ROOT.'/fichinter/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddIntervention").'</a>';
3191 }
3192 }*/
3193
3194 // Create contract
3195 $arrayforbutaction[] = array(
3196 'lang' => 'contracts',
3197 'enabled' => (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED),
3198 'perm' => $usercancreatecontract,
3199 'label' => 'AddContract',
3200 'url' => '/contrat/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3201 );
3202 /*if (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED) {
3203 $langs->load("contracts");
3204
3205 if ($usercancreatecontract) {
3206 print '<a class="butAction" href="'.DOL_URL_ROOT.'/contrat/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans('AddContract').'</a>';
3207 }
3208 }*/
3209
3210 // Create an invoice and classify billed
3211 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3212 $arrayforbutaction[] = [
3213 'lang' => 'invoice',
3214 'enabled' => isModEnabled('invoice'),
3215 'perm' => $usercancreateinvoice,
3216 'label' => 'CreateBill',
3217 'url' => '/compta/facture/card.php?action=create&origin='.urlencode($object->element).'&originid='.((int) $object->id).'&socid='.((int) $object->socid),
3218 ];
3219 /*if (isModEnabled('invoice') && $usercancreateinvoice) {
3220 print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/facture/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("CreateBill").'</a>';
3221 }*/
3222 }
3223
3224 $actionButtonsParameters = [
3225 "areDropdownButtons" => !getDolGlobalInt("MAIN_REMOVE_DROPDOWN_CREATE_BUTTONS_ON_ORDER"),
3226 "backtopage" => $_SERVER["PHP_SELF"] . "?id=" . ((int) $id)
3227 ];
3228
3229 if ($numlines > 0) {
3230 print dolGetButtonAction('', $langs->trans("Create"), 'default', $arrayforbutaction, $object->id, 1, $actionButtonsParameters);
3231 } else {
3232 print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans("Create"), 'default', $arrayforbutaction, $object->id, 0, $actionButtonsParameters);
3233 }
3234
3235 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3236 $arrayofinvoiceforpropal = $object->getInvoiceArrayList();
3237 if ((is_array($arrayofinvoiceforpropal) && count($arrayofinvoiceforpropal) > 0) || !getDolGlobalString('WORKFLOW_PROPAL_NEED_INVOICE_TO_BE_CLASSIFIED_BILLED')) {
3238 if ($usercanclose) {
3239 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=classifybilled&token='.newToken().'&socid='.$object->socid.'">'.$langs->trans("ClassifyBilled").'</a>';
3240 } else {
3241 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("ClassifyBilled").'</a>';
3242 }
3243 }
3244 }
3245
3246 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
3247 // Close as accepted/refused
3248 if ($object->status == Propal::STATUS_VALIDATED) {
3249 if ($usercanclose) {
3250 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=closeas&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close').'"';
3251 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3252 } else {
3253 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'"';
3254 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3255 }
3256 }
3257 } else {
3258 // Set not signed (close)
3259 if ($object->status == Propal::STATUS_DRAFT && $usercanclose) {
3260 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&token='.newToken().'&action=closeas&token='.newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
3261 print '>' . $langs->trans('SetRefusedAndClose') . '</a>';
3262 }
3263 }
3264
3265 // Cancel propal
3266 if ($object->status > Propal::STATUS_DRAFT && $usercanclose) {
3267 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=cancel&token='.newToken().'">'.$langs->trans("CancelPropal").'</a>';
3268 }
3269
3270 // Clone
3271 if ($usercancreate) {
3272 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&socid='.$object->socid.'&action=clone&token='.newToken().'&object='.$object->element.'">'.$langs->trans("ToClone").'</a>';
3273 }
3274
3275 // Delete
3276 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $usercandelete);
3277 }
3278 }
3279
3280 print '</div>';
3281 }
3282
3283 //Select mail models is same action as presend
3284 if (GETPOST('modelselected')) {
3285 $action = 'presend';
3286 }
3287
3288 if ($action != 'presend') {
3289 print '<div class="fichecenter"><div class="fichehalfleft">';
3290 print '<a name="builddoc"></a>'; // ancre
3291 /*
3292 * Generated documents
3293 */
3294 $objref = dol_sanitizeFileName($object->ref);
3295 $filedir = $conf->propal->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
3296 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
3297 $genallowed = $usercanread;
3298 $delallowed = $usercancreate;
3299
3300 print $formfile->showdocuments('propal', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang, '', $object);
3301
3302 // Show links to link elements
3303 $tmparray = $form->showLinkToObjectBlock($object, array(), array('propal'), 1);
3304 $linktoelem = $tmparray['linktoelem'];
3305 $htmltoenteralink = $tmparray['htmltoenteralink'];
3306 print $htmltoenteralink;
3307
3308 $compatibleImportElementsList = false;
3309 if ($user->hasRight('propal', 'creer') && $object->status == Propal::STATUS_DRAFT) {
3310 $compatibleImportElementsList = array('commande', 'propal', 'facture'); // import from linked elements
3311 }
3312 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
3313
3314 // Show online signature link
3315 $useonlinesignature = getDolGlobalInt('PROPOSAL_ALLOW_ONLINESIGN');
3316
3317 if ($object->status != Propal::STATUS_DRAFT && $useonlinesignature) {
3318 print '<br><!-- Link to sign -->';
3319 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
3320 print showOnlineSignatureUrl('proposal', $object->ref, $object).'<br>';
3321 }
3322
3323 print '</div><div class="fichehalfright">';
3324
3325 $MAXEVENT = 10;
3326
3327 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/comm/propal/agenda.php?id='.$object->id);
3328
3329 // List of actions on element
3330 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
3331 $formactions = new FormActions($db);
3332 $somethingshown = $formactions->showactions($object, 'propal', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
3333
3334 print '</div></div>';
3335 }
3336
3337 // Presend form
3338 $modelmail = 'propal_send';
3339 $defaulttopic = 'SendPropalRef';
3340 $diroutput = $conf->propal->multidir_output[$object->entity];
3341 $trackid = 'pro'.$object->id;
3342
3343 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
3344}
3345
3346// End of page
3347llxFooter();
3348$db->close();
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:87
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:71
Class to manage a WYSIWYG editor.
Class to manage standard extra fields.
static createDepositFromOrigin(CommonObject $origin, $date, $payment_terms_id, User $user, $notrigger=0, $autoValidateDeposit=false, $overrideFields=array())
Creates a deposit from a proposal or an order by grouping lines by VAT rates.
const TYPE_DEPOSIT
Deposit invoice.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
Class to manage generation of HTML components for proposal management.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation modules.
Class to manage the table of subscription to notifications.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage products or services.
Class to manage projects.
Class to manage proposals.
const STATUS_DRAFT
Draft status.
const STATUS_SIGNED
Signed quote.
const STATUS_NOTSIGNED
Not signed quote.
const STATUS_BILLED
Billed or processed quote.
const STATUS_CANCELED
Canceled status.
const STATUS_VALIDATED
Validated status.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0, $attop=0)
Set event message in dol_events session object.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
dol_clone($object, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
propal_prepare_head($object)
Prepare array with list of tabs.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.