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