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 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1612 $pu_equivalent = (float) $pu_ht_devise * (float) $currency_tx;
1613 }
1614 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1615 $pu_equivalent_ttc = (float) $pu_ttc_devise * (float) $currency_tx;
1616 }
1617
1618 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1619 /*
1620 if ($pu_equivalent) {
1621 $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
1622 $pu_equivalent_ttc = ...
1623 } else {
1624 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
1625 $pu_equivalent_ht = ...
1626 }
1627 */
1628
1629 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1630 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1631
1632 //$desc = dol_htmlcleanlastbr($desc);
1633
1634 // Check price is not lower than minimum
1635 if ($usermustrespectpricemin) {
1636 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
1637 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1638 setEventMessages($mesg, null, 'errors');
1639 $error++;
1640 } 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') {
1641 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1642 setEventMessages($mesg, null, 'errors');
1643 $error++;
1644 }
1645 }
1646
1647 if (!$error) {
1648 // Insert line
1649 $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);
1650
1651 if ($result > 0) {
1652 $db->commit();
1653
1654 $ret = $object->fetch($object->id); // Reload to get new records
1655 if ($ret > 0) {
1656 $object->fetch_thirdparty();
1657 }
1658
1659 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1660 // Define output language
1661 $outputlangs = $langs;
1662 $newlang = GETPOST('lang_id', 'alpha');
1663 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1664 $newlang = $object->thirdparty->default_lang;
1665 }
1666 if (!empty($newlang)) {
1667 $outputlangs = new Translate("", $conf);
1668 $outputlangs->setDefaultLang($newlang);
1669 }
1670 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1671 }
1672
1673 unset($_POST['prod_entry_mode']);
1674
1675 unset($_POST['qty']);
1676 unset($_POST['type']);
1677 unset($_POST['remise_percent']);
1678 unset($_POST['price_ht']);
1679 unset($_POST['multicurrency_price_ht']);
1680 unset($_POST['price_ttc']);
1681 unset($_POST['tva_tx']);
1682 unset($_POST['product_ref']);
1683 unset($_POST['product_label']);
1684 unset($_POST['product_desc']);
1685 unset($_POST['fournprice']);
1686 unset($_POST['buying_price']);
1687 unset($_POST['np_marginRate']);
1688 unset($_POST['np_markRate']);
1689 unset($_POST['dp_desc']);
1690 unset($_POST['idprod']);
1691 unset($_POST['units']);
1692
1693 unset($_POST['date_starthour']);
1694 unset($_POST['date_startmin']);
1695 unset($_POST['date_startsec']);
1696 unset($_POST['date_startday']);
1697 unset($_POST['date_startmonth']);
1698 unset($_POST['date_startyear']);
1699 unset($_POST['date_endhour']);
1700 unset($_POST['date_endmin']);
1701 unset($_POST['date_endsec']);
1702 unset($_POST['date_endday']);
1703 unset($_POST['date_endmonth']);
1704 unset($_POST['date_endyear']);
1705 } else {
1706 $db->rollback();
1707
1708 setEventMessages($object->error, $object->errors, 'errors');
1709 }
1710 }
1711 }
1712 } elseif ($action == 'addline' && $usercancreate && (
1713 (GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines', 'alpha') !== '') ||
1714 (GETPOST('submitforallmark', 'alpha') && GETPOST('markforalllines', 'alpha') !== ''))) {
1715 $outlangs = $langs;
1716 // Define margin
1717 $margin_rate = GETPOSTISSET('marginforalllines') ? GETPOST('marginforalllines', 'int') : '';
1718 $mark_rate = GETPOSTISSET('markforalllines') ? GETPOST('markforalllines', 'int') : '';
1719 foreach ($object->lines as &$line) if ($line->subprice > 0) {
1720 if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
1721 continue;
1722 }
1723 $subprice_multicurrency = $line->subprice;
1724 if (is_numeric($margin_rate) && $margin_rate > 0) {
1725 $line->subprice = floatval(price2num(floatval($line->pa_ht) * (1 + floatval($margin_rate) / 100), 'MU'));
1726 } elseif (is_numeric($mark_rate) && $mark_rate > 0) {
1727 $line->subprice = floatval($line->pa_ht / (1 - (floatval($mark_rate) / 100)));
1728 } else {
1729 $line->subprice = floatval($line->pa_ht);
1730 }
1731
1732 $prod = new Product($db);
1733 $res = $prod->fetch($line->fk_product);
1734 if ($res > 0) {
1735 if ($prod->price_min > $line->subprice) {
1736 $price_subprice = price($line->subprice, 0, $outlangs, 1, -1, -1, 'auto');
1737 $price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
1738 setEventMessages($prod->ref . ' - ' . $prod->label . ' (' . $price_subprice . ' < ' . $price_price_min . ' ' . strtolower($langs->trans("MinPrice")) . ')' . "\n", null, 'warnings');
1739 } else {
1740 setEventMessages($prod->error, $prod->errors, 'errors');
1741 }
1742 } else {
1743 setEventMessages($prod->error, $prod->errors, 'errors');
1744 }
1745
1746 // Manage $line->subprice and $line->multicurrency_subprice
1747 $multicurrency_subprice = (float) $line->subprice * $line->multicurrency_subprice / $subprice_multicurrency;
1748 // Update DB
1749 $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);
1750 // Update $object with new margin info
1751 if ($result > 0) {
1752 if (is_numeric($margin_rate) && empty($mark_rate)) {
1753 $line->marge_tx = $margin_rate;
1754 } elseif (is_numeric($mark_rate) && empty($margin_rate)) {
1755 $line->marque_tx = $mark_rate;
1756 }
1757 $line->total_ht = $line->qty * (float) $line->subprice;
1758 $line->total_tva = $line->tva_tx * $line->qty * (float) $line->subprice;
1759 $line->total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $line->subprice;
1760 // Manage $line->subprice and $line->multicurrency_subprice
1761 $line->multicurrency_total_ht = $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
1762 $line->multicurrency_total_tva = $line->tva_tx * $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
1763 $line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
1764 // Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
1765 $line->multicurrency_subprice = $multicurrency_subprice;
1766 } else {
1767 setEventMessages($object->error, $object->errors, 'errors');
1768 }
1769 }
1770 } elseif ($action == 'updatetitleline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
1771 // Handling updating a title line for subtotals module
1772
1773 $langs->load('subtotals');
1774
1775 $desc = GETPOST('line_desc', 'alphanohtml') ?? $langs->trans("Title");
1776 $depth = GETPOSTINT('line_depth') ?? 1;
1777
1778 $subtotal_options = array();
1779
1780 foreach (Propal::$TITLE_OPTIONS as $option) {
1781 $value = GETPOST($option, 'alphanohtml');
1782 if ($value) {
1783 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1784 }
1785 }
1786
1787 // Update line
1788 $result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
1789
1790 if ($result >= 0) {
1791 if ($result == 0) {
1792 setEventMessages($object->error, $object->errors, 'warnings');
1793 }
1794 $ret = $object->fetch($object->id); // Reload to get new records
1795 $object->fetch_thirdparty();
1796
1797 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1798 // Define output language
1799 $outputlangs = $langs;
1800 $newlang = GETPOST('lang_id', 'alpha');
1801 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1802 $newlang = $object->thirdparty->default_lang;
1803 }
1804 if (!empty($newlang)) {
1805 $outputlangs = new Translate("", $conf);
1806 $outputlangs->setDefaultLang($newlang);
1807 }
1808
1809 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1810 }
1811 } else {
1812 setEventMessages($object->error, $object->errors, 'errors');
1813 }
1814 } elseif ($action == 'updatesubtotalline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
1815 // Handling updating a subtotal line for subtotals module
1816
1817 $langs->load('subtotals');
1818
1819 $desc = GETPOST('line_desc', 'alphanohtml');
1820 $depth = GETPOSTINT('line_depth');
1821
1822 $subtotal_options = array();
1823
1824 foreach (Propal::$SUBTOTAL_OPTIONS as $option) {
1825 $value = GETPOST($option, 'alphanohtml');
1826 if ($value) {
1827 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1828 }
1829 }
1830
1831 // Update line
1832 $result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
1833
1834 if ($result > 0) {
1835 $ret = $object->fetch($object->id); // Reload to get new records
1836 $object->fetch_thirdparty();
1837
1838 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1839 // Define output language
1840 $outputlangs = $langs;
1841 $newlang = GETPOST('lang_id', 'alpha');
1842 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1843 $newlang = $object->thirdparty->default_lang;
1844 }
1845 if (!empty($newlang)) {
1846 $outputlangs = new Translate("", $conf);
1847 $outputlangs->setDefaultLang($newlang);
1848 }
1849
1850 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1851 }
1852 } else {
1853 setEventMessages($object->error, $object->errors, 'errors');
1854 }
1855 } elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
1856 // Update a line
1857
1858 // Clean parameters
1859 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
1860
1861 // Define info_bits
1862 $info_bits = 0;
1863 if (preg_match('/\*/', GETPOST('tva_tx'))) {
1864 $info_bits |= 0x01;
1865 }
1866
1867 // Define vat_rate
1868 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx', 'alpha') : 0);
1869 $vat_rate = str_replace('*', '', $vat_rate);
1870 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
1871 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
1872 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
1873 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
1874
1875 // Add buying price
1876 $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
1877 $buyingprice = price2num((GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''), '', 2); // If buying_price is '0', we must keep this value
1878
1879 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
1880 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
1881
1882 $date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), GETPOSTINT('date_startsec'), GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
1883 $date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), GETPOSTINT('date_endsec'), GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
1884
1885 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1886 if (empty($remise_percent)) {
1887 $remise_percent = 0;
1888 }
1889
1890 // Prepare a price equivalent for minimum price check
1891 $pu_equivalent = $pu_ht;
1892 $pu_equivalent_ttc = $pu_ttc;
1893
1894 $currency_tx = $object->multicurrency_tx;
1895
1896 // Check if we have a foreign currency
1897 // If so, we update the pu_equiv as the equivalent price in base currency
1898 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1899 $pu_equivalent = (float) $pu_ht_devise * (float) $currency_tx;
1900 }
1901 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1902 $pu_equivalent_ttc = (float) $pu_ttc_devise * (float) $currency_tx;
1903 }
1904
1905 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1906 /*
1907 if ($pu_equivalent) {
1908 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
1909 $pu_equivalent_ttc = ...
1910 } else {
1911 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
1912 $pu_equivalent_ht = ...
1913 }
1914 */
1915
1916 // Extrafields
1917 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1918 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
1919 // Unset extrafield
1920 if (is_array($extralabelsline)) {
1921 // Get extra fields
1922 foreach ($extralabelsline as $key => $value) {
1923 unset($_POST["options_".$key]);
1924 }
1925 }
1926
1927 // Define special_code for special lines
1928 $special_code = GETPOSTINT('special_code');
1929 if (!GETPOST('qty')) {
1930 $special_code = 3;
1931 }
1932
1933 $pu = $pu_ht;
1934 $price_base_type = 'HT';
1935 if (empty($pu) && !empty($pu_ttc)) {
1936 $pu = $pu_ttc;
1937 $price_base_type = 'TTC';
1938 }
1939
1940 // Check minimum price
1941 $productid = GETPOSTINT('productid');
1942 if (!empty($productid)) {
1943 $product = new Product($db);
1944 $res = $product->fetch($productid);
1945
1946 $type = $product->type;
1947
1948 // If base type TTc, we change pu value to define the TTC one
1949 if ($price_base_type == 'TTC' && !empty($pu_ttc)) {
1950 $pu = $pu_ttc;
1951 }
1952
1953 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
1954
1955 $price_min = $product->price_min;
1956 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1957 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
1958 }
1959 $price_min_ttc = $product->price_min_ttc;
1960 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1961 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
1962 }
1963
1964 //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1965 //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1966
1967 // Check price is not lower than minimum
1968 if ($usermustrespectpricemin) {
1969 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
1970 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1971 setEventMessages($mesg, null, 'errors');
1972 $error++;
1973 $action = 'editline';
1974 } 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') {
1975 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1976 setEventMessages($mesg, null, 'errors');
1977 $error++;
1978 $action = 'editline';
1979 }
1980 }
1981 } else {
1982 $type = GETPOST('type');
1983 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1984
1985 // Check parameters
1986 if (GETPOST('type') < 0) {
1987 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1988 $error++;
1989 }
1990 }
1991
1992 if (!$error) {
1993 $db->begin();
1994
1995 if (!$user->hasRight('margins', 'creer')) {
1996 foreach ($object->lines as &$line) {
1997 if ($line->id == GETPOSTINT('lineid')) {
1998 $fournprice = $line->fk_fournprice;
1999 $buyingprice = $line->pa_ht;
2000 break;
2001 }
2002 }
2003 }
2004
2005 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
2006
2007 $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);
2008
2009 if ($result >= 0) {
2010 $db->commit();
2011
2012 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
2013 // Define output language
2014 $outputlangs = $langs;
2015 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2016 $outputlangs = new Translate("", $conf);
2017 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
2018 $outputlangs->setDefaultLang($newlang);
2019 }
2020 $ret = $object->fetch($id); // Reload to get new records
2021 if ($ret > 0) {
2022 $object->fetch_thirdparty();
2023 }
2024 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
2025 }
2026
2027 unset($_POST['qty']);
2028 unset($_POST['type']);
2029 unset($_POST['productid']);
2030 unset($_POST['remise_percent']);
2031 unset($_POST['price_ht']);
2032 unset($_POST['multicurrency_price_ht']);
2033 unset($_POST['price_ttc']);
2034 unset($_POST['tva_tx']);
2035 unset($_POST['product_ref']);
2036 unset($_POST['product_label']);
2037 unset($_POST['product_desc']);
2038 unset($_POST['fournprice']);
2039 unset($_POST['buying_price']);
2040
2041 unset($_POST['date_starthour']);
2042 unset($_POST['date_startmin']);
2043 unset($_POST['date_startsec']);
2044 unset($_POST['date_startday']);
2045 unset($_POST['date_startmonth']);
2046 unset($_POST['date_startyear']);
2047 unset($_POST['date_endhour']);
2048 unset($_POST['date_endmin']);
2049 unset($_POST['date_endsec']);
2050 unset($_POST['date_endday']);
2051 unset($_POST['date_endmonth']);
2052 unset($_POST['date_endyear']);
2053 } else {
2054 $db->rollback();
2055
2056 setEventMessages($object->error, $object->errors, 'errors');
2057 }
2058 }
2059 } elseif ($action == 'updateline' && $usercancreate && GETPOST('cancel', 'alpha')) {
2060 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To re-display card in edit mode
2061 exit();
2062 } elseif ($action == 'classin' && $usercancreate) {
2063 // Set project
2064 $object->setProject(GETPOSTINT('projectid'));
2065 } elseif ($action == 'setavailability' && $usercancreate) {
2066 // Delivery time
2067 $result = $object->set_availability($user, GETPOSTINT('availability_id'));
2068 } elseif ($action == 'setdemandreason' && $usercancreate) {
2069 // Origin of the commercial proposal
2070 $result = $object->set_demand_reason($user, GETPOSTINT('demand_reason_id'));
2071 } elseif ($action == 'setconditions' && $usercancreate) {
2072 // Terms of payment
2073 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'), GETPOSTFLOAT('cond_reglement_id_deposit_percent'));
2074 } elseif ($action == 'setmode' && $usercancreate) {
2075 // Payment choice
2076 $result = $object->setPaymentMethods(GETPOSTINT('mode_reglement_id'));
2077 } elseif ($action == 'setmulticurrencycode' && $usercancreate) {
2078 // Multicurrency Code
2079 $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
2080 } elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
2081 // Multicurrency rate
2082 $result = $object->setMulticurrencyRate(GETPOSTFLOAT('multicurrency_tx'), GETPOSTINT('calculation_mode'));
2083 } elseif ($action == 'setbankaccount' && $usercancreate) {
2084 // bank account
2085 $result = $object->setBankAccount(GETPOSTINT('fk_account'));
2086 } elseif ($action == 'setshippingmethod' && $usercancreate) {
2087 // shipping method
2088 $result = $object->setShippingMethod(GETPOSTINT('shipping_method_id'));
2089 } elseif ($action == 'setwarehouse' && $usercancreate) {
2090 // warehouse
2091 $result = $object->setWarehouse(GETPOSTINT('warehouse_id'));
2092 } elseif ($action == 'update_extras' && $permissiontoeditextra) {
2093 $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
2094
2095 $attribute_name = GETPOST('attribute', 'aZ09');
2096
2097 // Fill array 'array_options' with data from update form
2098 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
2099 if ($ret < 0) {
2100 $error++;
2101 }
2102 if (!$error) {
2103 $result = $object->updateExtraField($attribute_name, 'PROPAL_MODIFY');
2104 if ($result < 0) {
2105 setEventMessages($object->error, $object->errors, 'errors');
2106 $error++;
2107 }
2108 }
2109 if ($error) {
2110 $action = 'edit_extras';
2111 }
2112 }
2113
2114 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
2115 if ($action == 'addcontact' && $usercancreate) {
2116 if ($object->id > 0) {
2117 $contactid = (GETPOST('userid') ? GETPOSTINT('userid') : GETPOSTINT('contactid'));
2118 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
2119 $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
2120 }
2121
2122 if ($result >= 0) {
2123 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
2124 exit();
2125 } else {
2126 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2127 $langs->load("errors");
2128 setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
2129 } else {
2130 setEventMessages($object->error, $object->errors, 'errors');
2131 }
2132 }
2133 } elseif ($action == 'swapstatut' && $usercancreate) {
2134 // Toggle the status of a contact
2135 if ($object->fetch($id) > 0) {
2136 $result = $object->swapContactStatus(GETPOSTINT('ligne'));
2137 } else {
2138 dol_print_error($db);
2139 }
2140 } elseif ($action == 'deletecontact' && $usercancreate) {
2141 // Delete a contact
2142 $object->fetch($id);
2143 $result = $object->delete_contact($lineid);
2144
2145 if ($result >= 0) {
2146 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
2147 exit();
2148 } else {
2149 dol_print_error($db);
2150 }
2151 }
2152 }
2153
2154 // Actions to build doc
2155 $upload_dir = !empty($conf->propal->multidir_output[$object->entity]) ? $conf->propal->multidir_output[$object->entity] : $conf->propal->dir_output;
2156 $permissiontoadd = $usercancreate;
2157 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
2158}
2159
2160
2161/*
2162 * View
2163 */
2164
2165$form = new Form($db);
2166$formfile = new FormFile($db);
2167$formpropal = new FormPropal($db);
2168$formmargin = new FormMargin($db);
2169$formproject = null;
2170if (isModEnabled('project')) {
2171 $formproject = new FormProjets($db);
2172}
2173
2174$title = $object->ref." - ".$langs->trans('Card');
2175if ($action == 'create') {
2176 $title = $langs->trans("NewPropal");
2177}
2178$help_url = 'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos|DE:Modul_Angebote';
2179
2180llxHeader('', $title, $help_url);
2181
2182$now = dol_now();
2183
2184// Add new proposal
2185if ($action == 'create') {
2186 $currency_code = $conf->currency;
2187
2188 print load_fiche_titre($langs->trans("NewProp"), '', 'propal');
2189
2190 $soc = new Societe($db);
2191 if ($socid > 0) {
2192 $res = $soc->fetch($socid);
2193 }
2194
2195 $currency_code = $conf->currency;
2196
2197 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
2198 $deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
2199 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
2200 $fk_account = GETPOSTINT('fk_account');
2201 $datepropal = (empty($datepropal) ? (!getDolGlobalString('MAIN_AUTOFILL_DATE_PROPOSAL') ? -1 : '') : $datepropal);
2202
2203 // Load objectsrc
2204 $objectsrc = null;
2205 if (!empty($origin) && !empty($originid)) {
2206 // Parse element/subelement (ex: project_task)
2207 $element = $subelement = $origin;
2208 $regs = array();
2209 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
2210 $element = $regs[1];
2211 $subelement = $regs[2];
2212 }
2213
2214 if ($element == 'project') {
2215 $projectid = $originid;
2216
2217 // Fetch project and thirdparty
2218 $project = new Project($db);
2219 $project->fetch($projectid);
2220 if ($project->socid > 0) {
2221 $soc = new Societe($db);
2222 $soc->fetch($project->socid);
2223 }
2224 } else {
2225 // For compatibility
2226 if ($element == 'order' || $element == 'commande') {
2227 $element = $subelement = 'commande';
2228 }
2229 if ($element == 'propal') {
2230 $element = 'comm/propal';
2231 $subelement = 'propal';
2232 }
2233 if ($element == 'contract') {
2234 $element = $subelement = 'contrat';
2235 }
2236 if ($element == 'shipping') {
2237 $element = $subelement = 'expedition';
2238 }
2239
2240 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
2241
2242 $classname = ucfirst($subelement);
2243 $objectsrc = new $classname($db);
2244 '@phan-var-force Commande|Propal|Contrat|Expedition $objectsrc'; // Can be other class, but CommonObject is too generic
2245 $objectsrc->fetch($originid);
2246 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
2247 $objectsrc->fetch_lines();
2248 }
2249 $objectsrc->fetch_thirdparty();
2250
2251 $projectid = (!empty($objectsrc->fk_project) ? $objectsrc->fk_project : 0);
2252 $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : '');
2253
2254 $soc = $objectsrc->thirdparty;
2255
2256 $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
2257 $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
2258 $warehouse_id = (!empty($objectsrc->warehouse_id) ? $objectsrc->warehouse_id : (!empty($soc->warehouse_id) ? $soc->warehouse_id : -1));
2259
2260 // Replicate extrafields
2261 $objectsrc->fetch_optionals();
2262 $object->array_options = $objectsrc->array_options;
2263
2264 if (isModEnabled("multicurrency")) {
2265 if (!empty($objectsrc->multicurrency_code)) {
2266 $currency_code = $objectsrc->multicurrency_code;
2267 }
2268 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
2269 $currency_tx = $objectsrc->multicurrency_tx;
2270 }
2271 }
2272 }
2273 }
2274
2275 // Load default values from thirdparty
2276 if (!empty($soc)) {
2277 $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
2278 $deposit_percent = empty($soc->deposit_percent) ? $deposit_percent : $soc->deposit_percent;
2279 $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
2280 $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
2281 $shipping_method_id = $soc->shipping_method_id;
2282 $warehouse_id = !empty($soc->fk_warehouse) ? $soc->fk_warehouse : $warehouse_id;
2283 $remise_percent = $soc->remise_percent;
2284
2285 if (isModEnabled("multicurrency") && !empty($soc->multicurrency_code)) {
2286 $currency_code = $soc->multicurrency_code;
2287 }
2288 }
2289
2290 // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
2291 if (!GETPOST('changecompany')) {
2292 if (GETPOSTISSET('cond_reglement_id')) {
2293 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
2294 }
2295 if (GETPOSTISSET('deposit_percent')) {
2296 $deposit_percent = price2num(GETPOST('deposit_percent', 'alpha'));
2297 }
2298 if (GETPOSTISSET('mode_reglement_id')) {
2299 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
2300 }
2301 if (GETPOSTISSET('fk_account')) {
2302 $fk_account = GETPOSTINT('fk_account');
2303 }
2304 }
2305 // Warehouse default if null
2306 if ($soc->fk_warehouse > 0) {
2307 $warehouse_id = $soc->fk_warehouse;
2308 }
2309 if (isModEnabled('stock') && $warehouse_id < 0 && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2310 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE')) {
2311 $warehouse_id = getDolGlobalString('MAIN_DEFAULT_WAREHOUSE');
2312 }
2313 if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && !empty($user->fk_warehouse)) {
2314 $warehouse_id = $user->fk_warehouse;
2315 }
2316 }
2317
2318 print '<form name="addprop" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2319 print '<input type="hidden" name="token" value="'.newToken().'">';
2320 print '<input type="hidden" name="action" value="add">';
2321 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
2322 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2323 if ($origin != 'project' && $originid) {
2324 print '<input type="hidden" name="origin" value="'.$origin.'">';
2325 print '<input type="hidden" name="originid" value="'.$originid.'">';
2326 } elseif ($origin == 'project' && !empty($projectid)) {
2327 print '<input type="hidden" name="projectid" value="'.$projectid.'">';
2328 }
2329
2330 print dol_get_fiche_head();
2331
2332 // Call Hook tabContentCreateProposal
2333 $parameters = array();
2334 // Note that $action and $object may be modified by hook
2335 $reshook = $hookmanager->executeHooks('tabContentCreateProposal', $parameters, $object, $action);
2336 if (empty($reshook)) {
2337 print '<table class="border centpercent">';
2338
2339 // Reference
2340 print '<tr class="field_ref"><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td><td class="valuefieldcreate">'.$langs->trans("Draft").'</td></tr>';
2341
2342 // Ref customer
2343 print '<tr class="field_ref_client"><td class="titlefieldcreate">'.$langs->trans('RefCustomer').'</td><td class="valuefieldcreate">';
2344 print '<input type="text" name="ref_client" value="'.(!empty($ref_client) ? $ref_client : GETPOST('ref_client')).'"></td>';
2345 print '</tr>';
2346
2347 // Third party
2348 print '<tr class="field_socid">';
2349 print '<td class="titlefieldcreate fieldrequired">'.$langs->trans('Customer').'</td>';
2350 if ($socid > 0) {
2351 print '<td class="valuefieldcreate">';
2352 print $soc->getNomUrl(1, 'customer');
2353 print '<input type="hidden" name="socid" value="'.$soc->id.'">';
2354 print '</td>';
2355 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2356 $shipping_method_id = $soc->shipping_method_id;
2357 }
2358 } else {
2359 print '<td class="valuefieldcreate">';
2360 $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
2361 print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company('', 'socid', $filter, 'SelectThirdParty', 1, 0, array(), 0, 'minwidth300 maxwidth500 widthcentpercentminusxx');
2362 // reload page to retrieve customer information
2363 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
2364 print '<script>
2365 $(document).ready(function() {
2366 $("#socid").change(function() {
2367 console.log("We have changed the company - Reload page");
2368 var socid = $(this).val();
2369 // reload page
2370 $("input[name=action]").val("create");
2371 $("input[name=changecompany]").val("1");
2372 $("form[name=addprop]").submit();
2373 });
2374 });
2375 </script>';
2376 }
2377 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>';
2378 print '</td>';
2379 }
2380 print '</tr>'."\n";
2381
2382 if ($socid > 0) {
2383 // Contacts (ask contact only if thirdparty already defined).
2384 print '<tr class="field_contactid"><td class="titlefieldcreate">'.$langs->trans("DefaultContact").'</td><td class="valuefieldcreate">';
2385 print img_picto('', 'contact', 'class="pictofixedwidth"');
2386 //print $form->selectcontacts($soc->id, $contactid, 'contactid', 1, '', '', 0, 'minwidth300 widthcentpercentminusx');
2387 print $form->select_contact($soc->id, $contactid, 'contactid', 1, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
2388 print '</td></tr>';
2389
2390 // Third party discounts info line
2391 print '<tr class="field_discount_info"><td class="titlefieldcreate">'.$langs->trans('Discounts').'</td><td class="valuefieldcreate">';
2392
2393 $absolute_discount = $soc->getAvailableDiscounts();
2394
2395 $thirdparty = $soc;
2396 $discount_type = 0;
2397 $backtopage = $_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.urlencode((string) (GETPOST('origin'))).'&originid='.urlencode((string) (GETPOSTINT('originid')));
2398 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
2399 print '</td></tr>';
2400 }
2401
2402 $newdatepropal = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'), 'tzserver');
2403 // Date
2404 print '<tr class="field_addprop"><td class="titlefieldcreate fieldrequired">'.$langs->trans('DatePropal').'</td><td class="valuefieldcreate">';
2405 print img_picto('', 'action', 'class="pictofixedwidth"');
2406 print $form->selectDate($newdatepropal ? $newdatepropal : $datepropal, '', 0, 0, 0, "addprop", 1, 1);
2407 print '</td></tr>';
2408
2409 // Validaty duration
2410 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>';
2411
2412 // Terms of payment
2413 print '<tr class="field_cond_reglement_id"><td class="nowrap">'.$langs->trans('PaymentConditionsShort').'</td><td>';
2414 print img_picto('', 'payment', 'class="pictofixedwidth"');
2415 // at last resort we take the payment term id which may be filled by default values set (if not getpostisset)
2416 print $form->getSelectConditionsPaiements((int) $cond_reglement_id, 'cond_reglement_id', 1, 1, 0, '', $deposit_percent);
2417 print '</td></tr>';
2418
2419 // Mode of payment
2420 print '<tr class="field_mode_reglement_id"><td class="titlefieldcreate">'.$langs->trans('PaymentMode').'</td><td class="valuefieldcreate">';
2421 print img_picto('', 'bank', 'class="pictofixedwidth"');
2422 print $form->select_types_paiements((string) $mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
2423 print '</td></tr>';
2424
2425 // Bank Account
2426 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
2427 print '<tr class="field_fk_account"><td class="titlefieldcreate">'.$langs->trans('BankAccount').'</td><td class="valuefieldcreate">';
2428 print img_picto('', 'bank_account', 'class="pictofixedwidth"').$form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
2429 print '</td></tr>';
2430 }
2431
2432 // Source / Channel - What trigger creation
2433 print '<tr class="field_demand_reason_id"><td class="titlefieldcreate">'.$langs->trans('Source').'</td><td class="valuefieldcreate">';
2434 print img_picto('', 'question', 'class="pictofixedwidth"');
2435 $form->selectInputReason((GETPOSTISSET('demand_reason_id') ? GETPOSTINT('demand_reason_id') : ''), 'demand_reason_id', "SRC_PROP", 1, 'maxwidth200 widthcentpercentminusx');
2436 print '</td></tr>';
2437
2438 // Shipping Method
2439 if (isModEnabled("shipping")) {
2440 if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
2441 $shipping_method_id = $soc->shipping_method_id;
2442 }
2443 print '<tr class="field_shipping_method_id"><td class="titlefieldcreate">'.$langs->trans('SendingMethod').'</td><td class="valuefieldcreate">';
2444 print img_picto('', 'dolly', 'class="pictofixedwidth"');
2445 $form->selectShippingMethod((string) (GETPOSTISSET('shipping_method_id') ? GETPOSTINT('shipping_method_id') : $shipping_method_id), 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx');
2446 print '</td></tr>';
2447 }
2448
2449 $formproduct = null;
2450 // Warehouse
2451 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
2452 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
2453 $formproduct = new FormProduct($db);
2454 print '<tr class="field_warehouse_id"><td class="titlefieldcreate">'.$langs->trans('Warehouse').'</td><td class="valuefieldcreate">';
2455 print img_picto('', 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx');
2456 print '</td></tr>';
2457 }
2458
2459 // Delivery delay
2460 print '<tr class="field_availability_id"><td class="titlefieldcreate">'.$langs->trans('AvailabilityPeriod');
2461 if (isModEnabled('order')) {
2462 print ' ('.$langs->trans('AfterOrder').')';
2463 }
2464 print '</td><td class="valuefieldcreate">';
2465 print img_picto('', 'clock', 'class="pictofixedwidth"');
2466 $form->selectAvailabilityDelay((GETPOSTISSET('availability_id') ? GETPOSTINT('availability_id') : ''), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx');
2467 print '</td></tr>';
2468
2469 // Delivery date (or manufacturing)
2470 print '<tr class="field_date_livraison"><td class="titlefieldcreate">'.$langs->trans("DeliveryDate").'</td>';
2471 print '<td class="valuefieldcreate">';
2472 print img_picto('', 'action', 'class="pictofixedwidth"');
2473 if (is_numeric(getDolGlobalString('DATE_LIVRAISON_WEEK_DELAY'))) { // If value set to 0 or a num, not empty
2474 $tmpdte = time() + (7 * getDolGlobalInt('DATE_LIVRAISON_WEEK_DELAY') * 24 * 60 * 60);
2475 $syear = date("Y", $tmpdte);
2476 $smonth = date("m", $tmpdte);
2477 $sday = date("d", $tmpdte);
2478 print $form->selectDate($syear."-".$smonth."-".$sday, 'date_livraison', 0, 0, 0, "addprop");
2479 } else {
2480 $tmp_date_delivery = GETPOST('date_delivery') ?: -1;
2481 print $form->selectDate($tmp_date_delivery, 'date_livraison', 0, 0, 0, "addprop", 1, 1);
2482 }
2483 print '</td></tr>';
2484
2485 // Project
2486 if (isModEnabled('project') && is_object($formproject)) {
2487 $langs->load("projects");
2488 print '<tr class="field_projectid">';
2489 print '<td class="titlefieldcreate">'.$langs->trans("Project").'</td><td class="valuefieldcreate">';
2490 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');
2491 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>';
2492 print '</td>';
2493 print '</tr>';
2494 }
2495
2496 // Incoterms
2497 if (isModEnabled('incoterm')) {
2498 print '<tr class="field_incoterm_id">';
2499 print '<td class="titlefieldcreate"><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $soc->label_incoterms, 1).'</label></td>';
2500 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2501 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
2502 print $form->select_incoterms((!empty($soc->fk_incoterms) ? $soc->fk_incoterms : ''), (!empty($soc->location_incoterms) ? $soc->location_incoterms : ''));
2503 print '</td></tr>';
2504 }
2505
2506 // Template to use by default
2507 print '<tr class="field_model">';
2508 print '<td class="titlefieldcreate">'.$langs->trans("DefaultModel").'</td>';
2509 print '<td class="valuefieldcreate">';
2510 print img_picto('', 'pdf', 'class="pictofixedwidth"');
2512 $preselected = (getDolGlobalString('PROPALE_ADDON_PDF_ODT_DEFAULT') ? $conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT : getDolGlobalString("PROPALE_ADDON_PDF"));
2513 print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
2514 print "</td></tr>";
2515
2516 // Multicurrency
2517 if (isModEnabled("multicurrency")) {
2518 print '<tr class="field_currency">';
2519 print '<td class="titlefieldcreate">'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
2520 print '<td class="valuefieldcreate maxwidthonsmartphone">';
2521 print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0, '', false, 'maxwidth200 widthcentpercentminusx');
2522 print '</td></tr>';
2523 }
2524
2525 // Public note
2526 print '<tr class="field_note_public">';
2527 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePublic').'</td>';
2528 print '<td class="valuefieldcreate">';
2529 $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');
2530 $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
2531 print $doleditor->Create(1);
2532
2533 // Private note
2534 if (empty($user->socid)) {
2535 print '<tr class="field_note_private">';
2536 print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePrivate').'</td>';
2537 print '<td class="valuefieldcreate">';
2538 $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc)) ? $objectsrc->note_private : null));
2539 $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
2540 print $doleditor->Create(1);
2541 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
2542 print '</td></tr>';
2543 }
2544
2545 // Other attributes
2546 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
2547
2548 // Lines from source
2549 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2550 // TODO for compatibility
2551 if ($origin == 'contrat') {
2552 // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
2553 //$objectsrc->remise_absolue = $remise_absolue; // deprecated
2554 //$objectsrc->remise_percent = $remise_percent;
2555 $objectsrc->update_price(1, 'auto', 1);
2556 }
2557
2558 print "\n<!-- ".$classname." info -->";
2559 print "\n";
2560 print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
2561 print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
2562 print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
2563 print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
2564 print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
2565
2566 $newclassname = $classname;
2567 if ($newclassname == 'Propal') {
2568 $newclassname = 'CommercialProposal';
2569 } elseif ($newclassname == 'Commande') {
2570 $newclassname = 'Order';
2571 } elseif ($newclassname == 'Expedition') {
2572 $newclassname = 'Sending';
2573 } elseif ($newclassname == 'Fichinter') {
2574 $newclassname = 'Intervention';
2575 }
2576
2577 print '<tr><td>'.$langs->trans($newclassname).'</td><td>'.$objectsrc->getNomUrl(1).'</td></tr>';
2578 print '<tr><td>'.$langs->trans('AmountHT').'</td><td>'.price($objectsrc->total_ht, 0, $langs, 1, -1, -1, $conf->currency).'</td></tr>';
2579 print '<tr><td>'.$langs->trans('AmountVAT').'</td><td>'.price($objectsrc->total_tva, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2580 if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
2581 print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2582 }
2583
2584 if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
2585 print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2586 }
2587 print '<tr><td>'.$langs->trans('AmountTTC').'</td><td>'.price($objectsrc->total_ttc, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2588
2589 if (isModEnabled("multicurrency")) {
2590 print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td>'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
2591 print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td>'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
2592 print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td>'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
2593 }
2594 }
2595
2596 print "</table>\n";
2597
2598
2599 /*
2600 * Combobox for copy function
2601 */
2602
2603 if (!getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2604 print '<input type="hidden" name="createmode" value="empty">';
2605 }
2606
2607 if (getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
2608 print '<br><table>';
2609
2610 // For backward compatibility
2611 print '<tr>';
2612 print '<td><input type="radio" name="createmode" value="copy"></td>';
2613 print '<td>'.$langs->trans("CopyPropalFrom").' </td>';
2614 print '<td>';
2615 $liste_propal = array();
2616 $liste_propal [0] = '';
2617
2618 $sql = "SELECT p.rowid as id, p.ref, s.nom";
2619 $sql .= " FROM ".MAIN_DB_PREFIX."propal p";
2620 $sql .= ", ".MAIN_DB_PREFIX."societe s";
2621 $sql .= " WHERE s.rowid = p.fk_soc";
2622 $sql .= " AND p.entity IN (".getEntity('propal').")";
2623 $sql .= " AND p.fk_statut <> 0";
2624 $sql .= " ORDER BY Id";
2625
2626 $resql = $db->query($sql);
2627 if ($resql) {
2628 $num = $db->num_rows($resql);
2629 $i = 0;
2630 while ($i < $num) {
2631 $row = $db->fetch_row($resql);
2632 $propalRefAndSocName = $row[1]." - ".$row[2];
2633 $liste_propal[$row[0]] = $propalRefAndSocName;
2634 $i++;
2635 }
2636 print $form->selectarray("copie_propal", $liste_propal, 0);
2637 } else {
2638 dol_print_error($db);
2639 }
2640 print '</td></tr>';
2641
2642 print '<tr><td class="tdtop"><input type="radio" name="createmode" value="empty" checked></td>';
2643 print '<td valign="top" colspan="2">'.$langs->trans("CreateEmptyPropal").'</td></tr>';
2644 print '</table>';
2645 }
2646 }
2647
2648 print dol_get_fiche_end();
2649
2650 $langs->load("bills");
2651
2652 print $form->buttonsSaveCancel("CreateDraft");
2653
2654 print "</form>";
2655
2656
2657 // Show origin lines
2658 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2659 print '<br>';
2660
2661 $title = $langs->trans('ProductsAndServices');
2662 print load_fiche_titre($title);
2663
2664 print '<div class="div-table-responsive-no-min">';
2665 print '<table class="noborder centpercent">';
2666
2667 $objectsrc->printOriginLinesList();
2668
2669 print '</table>';
2670 print '</div>';
2671 }
2672} elseif ($object->id > 0) {
2673 /*
2674 * Show object in view mode
2675 */
2676 $object->fetch_thirdparty();
2677 if ($object->thirdparty) {
2678 $soc = $object->thirdparty;
2679 } else {
2680 $soc = new Societe($db);
2681 }
2682
2684 print dol_get_fiche_head($head, 'comm', $langs->trans('Proposal'), -1, 'propal', 0, '', '', 0, '', 1);
2685
2686 $formconfirm = '';
2687
2688 // Clone confirmation
2689 if ($action == 'clone') {
2690 // Create an array for form
2691 $filter = '(s.client:IN:1,2,3)';
2692 $formquestion = array(
2693 // 'text' => $langs->trans("ConfirmClone"),
2694 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
2695 array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOSTINT('socid'), 'socid', $filter, '', 0, 0, array(), 0, 'maxwidth300')),
2696 array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0),
2697 array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0),
2698 );
2699 if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY') && !empty($object->delivery_date)) {
2700 $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date);
2701 }
2702 // Incomplete payment. We ask if reason = discount or other
2703 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmClonePropal', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 250, 600);
2704 }
2705
2706 // Subtotal line form
2707 if ($action == 'add_title_line') {
2708 $langs->load('subtotals');
2709 $type = 'title';
2710 $depth_array = $object->getPossibleLevels($langs);
2711 require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
2712 } elseif ($action == 'add_subtotal_line') {
2713 $langs->load('subtotals');
2714 $type = 'subtotal';
2715 $titles = $object->getPossibleTitles();
2716 require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
2717 }
2718
2719 if ($action == 'closeas') {
2720 //Form to close proposal (signed or not)
2721 $formquestion = array();
2722 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2723 $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)));
2724 }
2725 $formquestion[] = array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => ''); // Field to complete private note (not replace)
2726
2727 if (getDolGlobalInt('PROPOSAL_SUGGEST_DOWN_PAYMENT_INVOICE_CREATION')) {
2728 // This is a hidden option:
2729 // Suggestion to create invoice during proposal signature is not enabled by default.
2730 // Such choice should be managed by the workflow module and trigger. This option generates conflicts with some setup.
2731 // It may also break step of creating an order when invoicing must be done from orders and not from proposal
2732 $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
2733
2734 if (!empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')) {
2735 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
2736
2737 $object->fetchObjectLinked();
2738
2739 $eligibleForDepositGeneration = true;
2740
2741 if (array_key_exists('facture', $object->linkedObjects)) {
2742 foreach ($object->linkedObjects['facture'] as $invoice) {
2743 '@phan-var-force Facture $invoice';
2744 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2745 $eligibleForDepositGeneration = false;
2746 break;
2747 }
2748 }
2749 }
2750
2751 if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) {
2752 foreach ($object->linkedObjects['commande'] as $order) {
2753 $order->fetchObjectLinked();
2754
2755 if (array_key_exists('facture', $order->linkedObjects)) {
2756 foreach ($order->linkedObjects['facture'] as $invoice) {
2757 '@phan-var-force Facture $invoice';
2758 if ($invoice->type == Facture::TYPE_DEPOSIT) {
2759 $eligibleForDepositGeneration = false;
2760 break 2;
2761 }
2762 }
2763 }
2764 }
2765 }
2766
2767
2768 if ($eligibleForDepositGeneration) {
2769 $formquestion[] = array(
2770 'type' => 'checkbox',
2771 'tdclass' => 'showonlyifsigned',
2772 'name' => 'generate_deposit',
2773 'morecss' => 'margintoponly marginbottomonly',
2774 'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('DepositGenerationPermittedByThePaymentTermsSelected'))
2775 );
2776
2777 $formquestion[] = array(
2778 'type' => 'date',
2779 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2780 'name' => 'datef',
2781 'label' => $langs->trans('DateInvoice'),
2782 'value' => dol_now(),
2783 'datenow' => true
2784 );
2785
2786 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
2787 $formquestion[] = array(
2788 'type' => 'date',
2789 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2790 'name' => 'date_pointoftax',
2791 'label' => $langs->trans('DatePointOfTax'),
2792 'value' => dol_now(),
2793 'datenow' => true
2794 );
2795 }
2796
2797 $paymentTermsSelect = $form->getSelectConditionsPaiements(0, 'cond_reglement_id', -1, 0, 1, 'minwidth200');
2798
2799 $formquestion[] = array(
2800 'type' => 'other',
2801 'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2802 'name' => 'cond_reglement_id',
2803 'label' => $langs->trans('PaymentTerm'),
2804 'value' => $paymentTermsSelect
2805 );
2806
2807 $formquestion[] = array(
2808 'type' => 'checkbox',
2809 'tdclass' => 'showonlyifgeneratedeposit',
2810 'name' => 'validate_generated_deposit',
2811 'morecss' => 'margintoponly marginbottomonly',
2812 'label' => $langs->trans('ValidateGeneratedDeposit')
2813 );
2814
2815 $formquestion[] = array(
2816 'type' => 'onecolumn',
2817 'value' => '
2818 <script>
2819 let signedValue = ' . $object::STATUS_SIGNED . ';
2820
2821 $(document).ready(function() {
2822 $("[name=generate_deposit]").change(function () {
2823 let $self = $(this);
2824 let $target = $(".showonlyifgeneratedeposit").parent(".tagtr");
2825
2826 if (! $self.parents(".tagtr").is(":hidden") && $self.is(":checked")) {
2827 $target.show();
2828 } else {
2829 $target.hide();
2830 }
2831
2832 return true;
2833 });
2834
2835 $("#statut").change(function() {
2836 let $target = $(".showonlyifsigned").parent(".tagtr");
2837
2838 if ($(this).val() == signedValue) {
2839 $target.show();
2840 } else {
2841 $target.hide();
2842 }
2843
2844 $("[name=generate_deposit]").trigger("change");
2845
2846 return true;
2847 });
2848
2849 $("#statut").trigger("change");
2850 });
2851 </script>
2852 '
2853 );
2854 }
2855 }
2856 }
2857
2858 if (isModEnabled('notification')) {
2859 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2860 $notify = new Notify($db);
2861 $formquestion = array_merge($formquestion, array(
2862 array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)),
2863 ));
2864 }
2865
2866 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
2867 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetAcceptedRefused'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2868 } else {
2869 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?statut=3&id=' . $object->id, $langs->trans('Close'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2870 }
2871 } elseif ($action == 'cancel') {
2872 // Confirm cancel
2873 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("CancelPropal"), $langs->trans('ConfirmCancelPropal', $object->ref), 'confirm_cancel', '', 0, 1);
2874 } elseif ($action == 'delete') {
2875 // Confirm delete
2876 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp', $object->ref), 'confirm_delete', '', 0, 1);
2877 } elseif ($action == 'reopen') {
2878 // Confirm reopen
2879 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp', $object->ref), 'confirm_reopen', '', 0, 1);
2880 } elseif ($action == 'ask_deleteline') {
2881 // Confirmation delete product/service line
2882 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
2883 } elseif ($action == 'ask_subtotal_deleteline') {
2884 // Confirmation de la suppression d'une ligne subtotal
2885 $langs->load("subtotals");
2886 $title = "DeleteSubtotalLine";
2887 $question = "ConfirmDeleteSubtotalLine";
2888 if (GETPOST('type') == 'title') {
2889 $formconfirm = array(array('type' => 'checkbox', 'name' => 'deletecorrespondingsubtotalline', 'label' => $langs->trans("DeleteCorrespondingSubtotalLine"), 'value' => 0));
2890 $title = "DeleteTitleLine";
2891 $question = "ConfirmDeleteTitleLine";
2892 }
2893 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans($title), $langs->trans($question), 'confirm_delete_subtotalline', $formconfirm, 'no', 1);
2894 } elseif ($action == 'validate') {
2895 // Confirm validate proposal
2896 $error = 0;
2897
2898 // We verify whether the object is provisionally numbering
2899 $ref = substr($object->ref, 1, 4);
2900 if ($ref == 'PROV' || $ref == '') {
2901 $numref = $object->getNextNumRef($soc);
2902 if (empty($numref)) {
2903 $error++;
2904 setEventMessages($object->error, $object->errors, 'errors');
2905 }
2906 } else {
2907 $numref = $object->ref;
2908 }
2909
2910 $text = $langs->trans('ConfirmValidateProp', $numref);
2911 if (isModEnabled('notification')) {
2912 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2913 $notify = new Notify($db);
2914 $text .= '<br>';
2915 $text .= $notify->confirmMessage('PROPAL_VALIDATE', $object->socid, $object);
2916 }
2917
2918 // mandatoryPeriod
2919 $nbMandated = 0;
2920 foreach ($object->lines as $line) {
2921 $res = $line->fetch_product();
2922 if ($res > 0) {
2923 if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
2924 $nbMandated++;
2925 break;
2926 }
2927 }
2928 }
2929 if ($nbMandated > 0) {
2930 if (getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
2931 setEventMessages($langs->trans("mandatoryPeriodNeedTobeSetMsgValidate"), null, 'errors');
2932 $error++;
2933 } else {
2934 $text .= '<div><span class="clearboth nowraponall warning">'.img_warning().$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
2935 }
2936 }
2937
2938 if (!$error) {
2939 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateProp'), $text, 'confirm_validate', '', 0, 1, 240);
2940 }
2941 }
2942
2943 // Call Hook formConfirm
2944 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
2945 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2946 if (empty($reshook)) {
2947 $formconfirm .= $hookmanager->resPrint;
2948 } elseif ($reshook > 0) {
2949 $formconfirm = $hookmanager->resPrint;
2950 }
2951
2952 // Print form confirm
2953 print $formconfirm;
2954
2955
2956 // Proposal card
2957
2958 $linkback = '<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
2959
2960 $morehtmlref = '<div class="refidno">';
2961 // Ref customer
2962 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
2963 $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);
2964 // Thirdparty
2965 $morehtmlref .= '<br>'.$soc->getNomUrl(1, 'customer');
2966 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $soc->id > 0) {
2967 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?socid='.$soc->id.'&search_societe='.urlencode($soc->name).'">'.$langs->trans("OtherProposals").'</a>)';
2968 }
2969 // Project
2970 if (isModEnabled('project')) {
2971 $langs->load("projects");
2972 $morehtmlref .= '<br>';
2973 if ($usercancreate) {
2974 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2975 if ($action != 'classify') {
2976 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
2977 }
2978 $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');
2979 } else {
2980 if (!empty($object->fk_project)) {
2981 $proj = new Project($db);
2982 $proj->fetch($object->fk_project);
2983 $morehtmlref .= $proj->getNomUrl(1);
2984 if ($proj->title) {
2985 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
2986 }
2987 }
2988 }
2989 }
2990 $morehtmlref .= '</div>';
2991
2992
2993 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
2994
2995 // Call Hook tabContentViewProposal
2996 $parameters = array();
2997 // Note that $action and $object may be modified by hook
2998 $reshook = $hookmanager->executeHooks('tabContentViewProposal', $parameters, $object, $action);
2999 if (empty($reshook)) {
3000 print '<div class="fichecenter">';
3001 print '<div class="fichehalfleft">';
3002 print '<div class="underbanner clearboth"></div>';
3003
3004 print '<table class="border tableforfield centpercent">';
3005
3006 // Link for thirdparty discounts
3007 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
3008 $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
3009 $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
3010 } else {
3011 $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
3012 $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
3013 }
3014
3015 print '<tr><td class="titlefieldmax45">'.$langs->trans('Discounts').'</td><td>';
3016
3017 $absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount);
3018 $absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote);
3019 $absolute_discount = price2num($absolute_discount, 'MT');
3020 $absolute_creditnote = price2num($absolute_creditnote, 'MT');
3021
3022 $caneditfield = ($object->status != Propal::STATUS_SIGNED && $object->status != Propal::STATUS_BILLED);
3023
3024 $thirdparty = $soc;
3025 $discount_type = 0;
3026 $backtopage = $_SERVER["PHP_SELF"].'?id='.$object->id;
3027 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
3028
3029 print '</td></tr>';
3030
3031 // Date of proposal
3032 print '<tr>';
3033 print '<td>';
3034 // print '<table class="nobordernopadding" width="100%"><tr><td>';
3035 // print $langs->trans('DatePropal');
3036 // print '</td>';
3037 // if ($action != 'editdate' && $usercancreate && $caneditfield) {
3038 // 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>';
3039 // }
3040
3041 // print '</tr></table>';
3042 $editenable = $usercancreate && $caneditfield && $object->status == Propal::STATUS_DRAFT;
3043 print $form->editfieldkey("DatePropal", 'date', '', $object, (int) $editenable);
3044 print '</td><td class="valuefield">';
3045 if ($action == 'editdate' && $usercancreate && $caneditfield) {
3046 print '<form name="editdate" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
3047 print '<input type="hidden" name="token" value="'.newToken().'">';
3048 print '<input type="hidden" name="action" value="setdate">';
3049 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
3050 print $form->selectDate($object->date, 're', 0, 0, 0, "editdate");
3051 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
3052 print '</form>';
3053 } else {
3054 if ($object->date) {
3055 print dol_print_date($object->date, 'day');
3056 } else {
3057 print '&nbsp;';
3058 }
3059 }
3060 print '</td>';
3061
3062 // Date end proposal
3063 print '<tr>';
3064 print '<td>';
3065 print '<table class="nobordernopadding centpercent"><tr><td>';
3066 print $langs->trans('DateEndPropal');
3067 print '</td>';
3068 if ($action != 'editecheance' && $usercancreate && $caneditfield) {
3069 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>';
3070 }
3071 print '</tr></table>';
3072 print '</td><td class="valuefield">';
3073 if ($action == 'editecheance' && $usercancreate && $caneditfield) {
3074 print '<form name="editecheance" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
3075 print '<input type="hidden" name="token" value="'.newToken().'">';
3076 print '<input type="hidden" name="action" value="setecheance">';
3077 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
3078 print $form->selectDate($object->fin_validite, 'ech', 0, 0, 0, "editecheance");
3079 print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
3080 print '</form>';
3081 } else {
3082 if (!empty($object->fin_validite)) {
3083 print dol_print_date($object->fin_validite, 'day');
3084 if ($object->status == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) {
3085 print img_warning($langs->trans("Late"));
3086 }
3087 } else {
3088 print '&nbsp;';
3089 }
3090 }
3091 print '</td>';
3092 print '</tr>';
3093
3094 // Payment term
3095 print '<tr><td>';
3096 print '<table class="nobordernopadding centpercent"><tr><td>';
3097 print $langs->trans('PaymentConditionsShort');
3098 print '</td>';
3099 if ($action != 'editconditions' && $usercancreate && $caneditfield) {
3100 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>';
3101 }
3102 print '</tr></table>';
3103 print '</td><td class="valuefield">';
3104 if ($action == 'editconditions' && $usercancreate && $caneditfield) {
3105 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->cond_reglement_id, 'cond_reglement_id', 0, '', 1, $object->deposit_percent);
3106 } else {
3107 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->cond_reglement_id, 'none', 0, '', 1, $object->deposit_percent);
3108 }
3109 print '</td>';
3110 print '</tr>';
3111
3112 // Payment mode
3113 print '<tr class="field_mode_reglement_id">';
3114 print '<td>';
3115 print '<table class="nobordernopadding centpercent"><tr><td>';
3116 print $langs->trans('PaymentMode');
3117 print '</td>';
3118 if ($action != 'editmode' && $usercancreate && $caneditfield) {
3119 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>';
3120 }
3121 print '</tr></table>';
3122 print '</td><td class="valuefieldcreate">';
3123 if ($action == 'editmode' && $usercancreate && $caneditfield) {
3124 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
3125 } else {
3126 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->mode_reglement_id, 'none');
3127 }
3128 print '</td></tr>';
3129
3130 // Delivery date
3131 $langs->load('deliveries');
3132 print '<tr><td>';
3133 print $form->editfieldkey($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, (int) ($usercancreate && $caneditfield), 'datepicker');
3134 print '</td><td class="valuefieldedit">';
3135 print $form->editfieldval($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
3136 print '</td>';
3137 print '</tr>';
3138
3139 // Delivery delay
3140 print '<tr class="fielddeliverydelay"><td>';
3141 print '<table class="nobordernopadding centpercent"><tr><td>';
3142 if (isModEnabled('order')) {
3143 print $form->textwithpicto($langs->trans('AvailabilityPeriod'), $langs->trans('AvailabilityPeriod').' ('.$langs->trans('AfterOrder').')');
3144 } else {
3145 print $langs->trans('AvailabilityPeriod');
3146 }
3147 print '</td>';
3148 if ($action != 'editavailability' && $usercancreate && $caneditfield) {
3149 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>';
3150 }
3151 print '</tr></table>';
3152 print '</td><td class="valuefield">';
3153 if ($action == 'editavailability' && $usercancreate && $caneditfield) {
3154 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->availability_id, 'availability_id', 1);
3155 } else {
3156 $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->availability_id, 'none', 1);
3157 }
3158
3159 print '</td>';
3160 print '</tr>';
3161
3162 // Shipping Method
3163 if (isModEnabled("shipping")) {
3164 print '<tr><td>';
3165 print '<table class="nobordernopadding centpercent"><tr><td>';
3166 print $langs->trans('SendingMethod');
3167 print '</td>';
3168 if ($action != 'editshippingmethod' && $usercancreate && $caneditfield) {
3169 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>';
3170 }
3171 print '</tr></table>';
3172 print '</td><td class="valuefield">';
3173 if ($action == 'editshippingmethod' && $usercancreate && $caneditfield) {
3174 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->shipping_method_id, 'shipping_method_id', 1);
3175 } else {
3176 $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->shipping_method_id, 'none');
3177 }
3178 print '</td>';
3179 print '</tr>';
3180 }
3181
3182 // Warehouse
3183 if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
3184 $langs->load('stocks');
3185 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
3186 $formproduct = new FormProduct($db);
3187 print '<tr class="field_warehouse_id"><td>';
3188 $editenable = $usercancreate;
3189 print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable);
3190 print '</td><td class="valuefieldcreate">';
3191 if ($action == 'editwarehouse') {
3192 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1);
3193 } else {
3194 $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'none');
3195 }
3196 print '</td>';
3197 print '</tr>';
3198 }
3199
3200 // Origin of demand
3201 print '<tr><td>';
3202 print '<table class="nobordernopadding centpercent"><tr><td>';
3203 print $langs->trans('Source');
3204 print '</td>';
3205 if ($action != 'editdemandreason' && $usercancreate) {
3206 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>';
3207 }
3208 print '</tr></table>';
3209 print '</td><td class="valuefield">';
3210 if ($action == 'editdemandreason' && $usercancreate) {
3211 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->demand_reason_id, 'demand_reason_id', 1);
3212 } else {
3213 $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->demand_reason_id, 'none');
3214 }
3215 print '</td>';
3216 print '</tr>';
3217
3218 if ($soc->outstanding_limit) {
3219 // Outstanding Bill
3220 print '<tr><td>';
3221 print $langs->trans('OutstandingBill');
3222 print '</td><td class="valuefield">';
3223 $arrayoutstandingbills = $soc->getOutstandingBills();
3224 print($arrayoutstandingbills['opened'] > $soc->outstanding_limit ? img_warning() : '');
3225 print price($arrayoutstandingbills['opened']).' / ';
3226 print price($soc->outstanding_limit, 0, $langs, 1, - 1, - 1, $conf->currency);
3227 print '</td>';
3228 print '</tr>';
3229 }
3230
3231 if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
3232 // Bank Account
3233 print '<tr><td>';
3234 print '<table width="100%" class="nobordernopadding"><tr><td>';
3235 print $langs->trans('BankAccount');
3236 print '</td>';
3237 if ($action != 'editbankaccount' && $usercancreate) {
3238 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>';
3239 }
3240 print '</tr></table>';
3241 print '</td><td class="valuefield">';
3242 if ($action == 'editbankaccount') {
3243 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'fk_account', 1);
3244 } else {
3245 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'none');
3246 }
3247 print '</td>';
3248 print '</tr>';
3249 }
3250
3251 if (!getDolGlobalString('PROPOSAL_HIDE_CALCULATED_WEIGHT_VOLUME')) {
3252 $tmparray = $object->getTotalWeightVolume();
3253 $totalWeight = isset($tmparray['weight']) ? $tmparray['weight'] : 0;
3254 $totalVolume = isset($tmparray['volume']) ? $tmparray['volume'] : 0;
3255 if ($totalWeight) {
3256 print '<tr><td>'.$langs->trans("CalculatedWeight").'</td>';
3257 print '<td class="valuefield">';
3258 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 'no'), 1);
3259 print '</td></tr>';
3260 }
3261 if ($totalVolume) {
3262 print '<tr><td>'.$langs->trans("CalculatedVolume").'</td>';
3263 print '<td class="valuefield">';
3264 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'), 1);
3265 print '</td></tr>';
3266 }
3267 }
3268
3269 // Incoterms
3270 if (isModEnabled('incoterm')) {
3271 print '<tr><td>';
3272 print '<table width="100%" class="nobordernopadding"><tr><td>';
3273 print $langs->trans('IncotermLabel');
3274 print '<td><td class="right">';
3275 if ($action != 'editincoterm' && $usercancreate && $caneditfield) {
3276 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/comm/propal/card.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
3277 } else {
3278 print '&nbsp;';
3279 }
3280 print '</td></tr></table>';
3281 print '</td>';
3282 print '<td class="valuefield">';
3283 if ($action == 'editincoterm' && $usercancreate && $caneditfield) {
3284 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
3285 } else {
3286 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
3287 }
3288 print '</td></tr>';
3289 }
3290
3291 // Other attributes
3292 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
3293
3294 print '</table>';
3295
3296 print '</div>';
3297 print '<div class="fichehalfright">';
3298 print '<div class="underbanner clearboth"></div>';
3299
3300 print '<table class="border tableforfield centpercent">';
3301
3302 include DOL_DOCUMENT_ROOT.'/core/tpl/object_currency_amount.tpl.php';
3303
3304 print '<tr>';
3305 print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
3306 print '<td class="nowrap amountcard right">' . price($object->total_ht, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3307 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3308 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ht, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3309 }
3310 print '</tr>';
3311
3312 print '<tr>';
3313 print '<td>' . $langs->trans('AmountVAT') . '</td>';
3314 print '<td class="nowrap amountcard right">' . price($object->total_tva, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3315 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3316 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_tva, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3317 }
3318 print '</tr>';
3319
3320 if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
3321 print '<tr>';
3322 print '<td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
3323 print '<td class="nowrap amountcard right">' . price($object->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3324 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3325 $object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
3326
3327 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3328 }
3329 print '</tr>';
3330 }
3331
3332 if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
3333 print '<tr>';
3334 print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
3335 print '<td class="nowrap amountcard right">' . price($object->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3336 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3337 $object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
3338
3339 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3340 }
3341 print '</tr>';
3342 }
3343
3344 print '<tr>';
3345 print '<td>' . $langs->trans('AmountTTC') . '</td>';
3346 print '<td class="nowrap amountcard right">' . price($object->total_ttc, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
3347 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
3348 print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ttc, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
3349 }
3350 print '</tr>';
3351
3352 print '</table>';
3353
3354 // Margin Infos
3355 if (isModEnabled('margin')) {
3356 $formmargin->displayMarginInfos($object);
3357 }
3358
3359 print '</div>';
3360 print '</div>';
3361
3362 print '<div class="clearboth"></div><br>';
3363
3364 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
3365 $blocname = 'contacts';
3366 $title = $langs->trans('ContactsAddresses');
3367 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
3368 }
3369
3370 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
3371 $blocname = 'notes';
3372 $title = $langs->trans('Notes');
3373 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
3374 }
3375
3376 /*
3377 * Lines
3378 */
3379
3380 // Get object lines
3381 $result = $object->getLinesArray();
3382
3383 // Add products/services form
3384 //$forceall = 1;
3385 global $inputalsopricewithtax;
3386 $inputalsopricewithtax = 1;
3387
3388 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
3389 <input type="hidden" name="token" value="' . newToken().'">
3390 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
3391 <input type="hidden" name="mode" value="">
3392 <input type="hidden" name="page_y" value="">
3393 <input type="hidden" name="backtopage" value="'.$backtopage.'">
3394 <input type="hidden" name="id" value="' . $object->id.'">
3395 ';
3396
3397 if (!empty($conf->use_javascript_ajax) && $object->status == Propal::STATUS_DRAFT) {
3398 if (isModEnabled('subtotals')) {
3399 include DOL_DOCUMENT_ROOT.'/core/tpl/subtotal_ajaxrow.tpl.php';
3400 } else {
3401 include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
3402 }
3403 }
3404
3405 print '<div class="div-table-responsive-no-min">';
3406 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3407 print '<table id="tablelines" class="noborder noshadow centpercent">';
3408 }
3409
3410 if (!empty($object->lines)) {
3411 $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 1);
3412 }
3413
3414 // Form to add new line
3415 if ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines') {
3416 if ($action != 'editline') {
3417 $parameters = array();
3418 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3419 if ($reshook < 0) {
3420 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3421 }
3422 if (empty($reshook)) {
3423 $object->formAddObjectLine(1, $mysoc, $soc);
3424 }
3425 } else {
3426 $parameters = array();
3427 $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3428 }
3429 }
3430
3431 if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
3432 print '</table>';
3433 }
3434 print '</div>';
3435
3436 print "</form>\n";
3437 }
3438
3439 print dol_get_fiche_end();
3440
3441
3442 /*
3443 * Button Actions
3444 */
3445
3446 if ($action != 'presend') {
3447 $numlines = count($object->lines);
3448 print '<div class="tabsAction">';
3449
3450 $parameters = array();
3451 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
3452 // modified by hook
3453 if (empty($reshook)) {
3454 if ($action != 'editline') {
3455 // Subtotal
3456 if ($object->status == Propal::STATUS_DRAFT && isModEnabled('subtotals')
3457 && (getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element)) || getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element)))) {
3458 $langs->load('subtotals');
3459
3460 $url_button = array();
3461
3462 $url_button[] = array(
3463 'lang' => 'subtotals',
3464 'enabled' => (isModEnabled('propal') && $object->status == Propal::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element))),
3465 'perm' => (bool) $usercancreate,
3466 'label' => $langs->trans('AddTitleLine'),
3467 'url' => '/comm/propal/card.php?id='.$object->id.'&action=add_title_line&token='.newToken()
3468 );
3469
3470 $url_button[] = array(
3471 'lang' => 'subtotals',
3472 'enabled' => (isModEnabled('propal') && $object->status == Propal::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element))),
3473 'perm' => (bool) $usercancreate,
3474 'label' => $langs->trans('AddSubtotalLine'),
3475 'url' => '/comm/propal/card.php?id='.$object->id.'&action=add_subtotal_line&token='.newToken()
3476 );
3477
3478 print dolGetButtonAction('', $langs->trans('Subtotal'), 'default', $url_button, '', true);
3479 }
3480
3481 // Validate
3482 if (($object->status == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0)
3483 || ($object->status == Propal::STATUS_DRAFT && getDolGlobalString('PROPAL_ENABLE_NEGATIVE') && count($object->lines) > 0)) {
3484 if ($usercanvalidate) {
3485 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>';
3486 } else {
3487 print '<a class="butActionRefused classfortooltip" href="#">'.$langs->trans('Validate').'</a>';
3488 }
3489 }
3490 // Create event
3491 /*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.
3492 {
3493 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>';
3494 }*/
3495 // Edit
3496 if ($object->status == Propal::STATUS_VALIDATED && $usercancreate) {
3497 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=modif&token='.newToken().'">'.$langs->trans('Modify').'</a>';
3498 }
3499
3500 // ReOpen
3501 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)))) {
3502 if ($usercanreopen) {
3503 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#reopen').'"';
3504 print '>'.$langs->trans('ReOpen').'</a>';
3505 } else {
3506 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("ReOpen").'</a>';
3507 }
3508 }
3509
3510 // Send
3511 if (empty($user->socid)) {
3512 if ($object->status == Propal::STATUS_VALIDATED || $object->status == Propal::STATUS_SIGNED || getDolGlobalString('PROPOSAL_SENDBYEMAIL_FOR_ALL_STATUS')) {
3513 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '', $usercansend);
3514 }
3515 }
3516
3517 $arrayforbutaction = array();
3518
3519 // Create a sale order
3520 $arrayforbutaction[] = array(
3521 'lang' => 'orders',
3522 'enabled' => (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED),
3523 'perm' => $usercancreateorder,
3524 'label' => 'AddOrder',
3525 'url' => '/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3526 );
3527 /*if (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED) {
3528 if ($usercancreateorder) {
3529 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>';
3530 }
3531 }*/
3532
3533 // Create a purchase order
3534 if (getDolGlobalString('WORKFLOW_CAN_CREATE_PURCHASE_ORDER_FROM_PROPOSAL')) {
3535 $arrayforbutaction[] = array(
3536 'lang' => 'orders',
3537 'enabled' => ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")),
3538 'perm' => $usercancreatepurchaseorder,
3539 'label' => 'AddPurchaseOrder',
3540 'url' => '/fourn/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3541 );
3542 /*if ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")) {
3543 if ($usercancreatepurchaseorder) {
3544 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>';
3545 }
3546 }*/
3547 }
3548
3549 // Create an intervention
3550 $arrayforbutaction[] = array(
3551 'lang' => 'interventions',
3552 'enabled' => (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED),
3553 'perm' => $usercancreateintervention,
3554 'label' => 'AddIntervention',
3555 'url' => '/fichinter/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3556 );
3557 /*if (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED) {
3558 if ($usercancreateintervention) {
3559 $langs->load("interventions");
3560 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>';
3561 }
3562 }*/
3563
3564 // Create contract
3565 $arrayforbutaction[] = array(
3566 'lang' => 'contracts',
3567 'enabled' => (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED),
3568 'perm' => $usercancreatecontract,
3569 'label' => 'AddContract',
3570 'url' => '/contrat/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
3571 );
3572 /*if (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED) {
3573 $langs->load("contracts");
3574
3575 if ($usercancreatecontract) {
3576 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>';
3577 }
3578 }*/
3579
3580 // Create an invoice and classify billed
3581 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3582 $arrayforbutaction[] = [
3583 'lang' => 'invoice',
3584 'enabled' => isModEnabled('invoice'),
3585 'perm' => $usercancreateinvoice,
3586 'label' => 'CreateBill',
3587 'url' => '/compta/facture/card.php?action=create&origin='.urlencode($object->element).'&originid='.((int) $object->id).'&socid='.((int) $object->socid),
3588 ];
3589 /*if (isModEnabled('invoice') && $usercancreateinvoice) {
3590 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>';
3591 }*/
3592 }
3593
3594 $actionButtonsParameters = [
3595 "areDropdownButtons" => !getDolGlobalInt("MAIN_REMOVE_DROPDOWN_CREATE_BUTTONS_ON_ORDER"),
3596 "backtopage" => $_SERVER["PHP_SELF"] . "?id=" . ((int) $id)
3597 ];
3598
3599 if ($numlines > 0) {
3600 print dolGetButtonAction('', $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 1, $actionButtonsParameters);
3601 } else {
3602 print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 0, $actionButtonsParameters);
3603 }
3604
3605 if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
3606 $arrayofinvoiceforpropal = $object->getInvoiceArrayList();
3607 if ((is_array($arrayofinvoiceforpropal) && count($arrayofinvoiceforpropal) > 0) || !getDolGlobalString('WORKFLOW_PROPAL_NEED_INVOICE_TO_BE_CLASSIFIED_BILLED')) {
3608 if ($usercanclose) {
3609 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=classifybilled&token='.newToken().'&socid='.$object->socid.'">'.$langs->trans("ClassifyBilled").'</a>';
3610 } else {
3611 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("ClassifyBilled").'</a>';
3612 }
3613 }
3614 }
3615
3616 if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
3617 // Close as accepted/refused
3618 if ($object->status == Propal::STATUS_VALIDATED) {
3619 if ($usercanclose) {
3620 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=closeas&token='.newToken().(!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close').'"';
3621 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3622 } else {
3623 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'"';
3624 print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3625 }
3626 }
3627 } else {
3628 // Set not signed (close)
3629 if ($object->status == Propal::STATUS_DRAFT && $usercanclose) {
3630 print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&token='.newToken().'&action=closeas&token='.newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
3631 print '>' . $langs->trans('SetRefusedAndClose') . '</a>';
3632 }
3633 }
3634
3635 // Cancel propal
3636 if ($object->status > Propal::STATUS_DRAFT && $usercanclose) {
3637 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=cancel&token='.newToken().'">'.$langs->trans("CancelPropal").'</a>';
3638 }
3639
3640 // Clone
3641 if ($usercancreate) {
3642 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>';
3643 }
3644
3645 // Delete
3646 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $usercandelete);
3647 }
3648 }
3649
3650 print '</div>';
3651 }
3652
3653 //Select mail models is same action as presend
3654 if (GETPOST('modelselected')) {
3655 $action = 'presend';
3656 }
3657
3658 if ($action != 'presend') {
3659 print '<div class="fichecenter"><div class="fichehalfleft">';
3660 print '<a name="builddoc"></a>'; // ancre
3661 /*
3662 * Generated documents
3663 */
3664 $objref = dol_sanitizeFileName($object->ref);
3665 $filedir = $conf->propal->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
3666 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
3667 $genallowed = $usercanread;
3668 $delallowed = $usercancreate;
3669
3670 print $formfile->showdocuments('propal', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '0', '', $soc->default_lang, '', $object);
3671
3672 // Show links to link elements
3673 $tmparray = $form->showLinkToObjectBlock($object, array(), array('propal'), 1);
3674 $linktoelem = $tmparray['linktoelem'];
3675 $htmltoenteralink = $tmparray['htmltoenteralink'];
3676 print $htmltoenteralink;
3677
3678 $compatibleImportElementsList = false;
3679 if ($user->hasRight('propal', 'creer') && $object->status == Propal::STATUS_DRAFT) {
3680 $compatibleImportElementsList = array('commande', 'propal', 'facture', 'subscription'); // import from linked elements
3681 }
3682 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
3683
3684 // Show online signature link
3685 $useonlinesignature = getDolGlobalInt('PROPOSAL_ALLOW_ONLINESIGN');
3686
3687 if ($object->status != Propal::STATUS_DRAFT && $useonlinesignature) {
3688 print '<br><!-- Link to sign -->';
3689 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
3690 print showOnlineSignatureUrl('proposal', $object->ref, $object).'<br>';
3691 }
3692
3693 print '</div><div class="fichehalfright">';
3694
3695 $MAXEVENT = 10;
3696
3697 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/comm/propal/agenda.php?id='.$object->id);
3698
3699 // List of actions on element
3700 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
3701 $formactions = new FormActions($db);
3702 $somethingshown = $formactions->showactions($object, 'propal', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
3703
3704 print '</div></div>';
3705 }
3706
3707 // Presend form
3708 $modelmail = 'propal_send';
3709 $defaulttopic = 'SendPropalRef';
3710 $diroutput = $conf->propal->multidir_output[$object->entity];
3711 $trackid = 'pro'.$object->id;
3712
3713 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
3714}
3715
3716// End of page
3717llxFooter();
3718$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.