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