dolibarr  18.0.6
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 (!($socid > 0)) {
183  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('IdThirdParty')), 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  $locationTarget = '';
706  // prevent browser refresh from closing proposal several times
707  if ($object->statut == $object::STATUS_VALIDATED || ( ! empty($conf->global->PROPAL_SKIP_ACCEPT_REFUSE) && $object->statut == $object::STATUS_DRAFT)) {
708  $db->begin();
709 
710  $result = $object->closeProposal($user, GETPOST('statut', 'int'), GETPOST('note_private', 'restricthtml'));
711  if ($result < 0) {
712  setEventMessages($object->error, $object->errors, 'errors');
713  $error++;
714  } else {
715  // Needed if object linked modified by trigger (because linked objects can't be fetched two times : linkedObjectsFullLoaded)
716  $locationTarget = DOL_URL_ROOT . '/comm/propal/card.php?id=' . $object->id;
717  }
718 
719  $deposit = null;
720 
721  $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
722 
723  if (
724  !$error && GETPOST('statut', 'int') == $object::STATUS_SIGNED && GETPOST('generate_deposit', 'alpha') == 'on'
725  && !empty($deposit_percent_from_payment_terms) && isModEnabled('facture') && !empty($user->rights->facture->creer)
726  ) {
727  require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
728 
729  $date = dol_mktime(0, 0, 0, GETPOST('datefmonth', 'int'), GETPOST('datefday', 'int'), GETPOST('datefyear', 'int'));
730  $forceFields = array();
731 
732  if (GETPOSTISSET('date_pointoftax')) {
733  $forceFields['date_pointoftax'] = dol_mktime(0, 0, 0, GETPOST('date_pointoftaxmonth', 'int'), GETPOST('date_pointoftaxday', 'int'), GETPOST('date_pointoftaxyear', 'int'));
734  }
735 
736  $deposit = Facture::createDepositFromOrigin($object, $date, GETPOST('cond_reglement_id', 'int'), $user, 0, GETPOST('validate_generated_deposit', 'alpha') == 'on', $forceFields);
737 
738  if ($deposit) {
739  setEventMessage('DepositGenerated');
740  $locationTarget = DOL_URL_ROOT . '/compta/facture/card.php?id=' . $deposit->id;
741  } else {
742  $error++;
743  setEventMessages($object->error, $object->errors, 'errors');
744  }
745  }
746 
747  if (!$error) {
748  $db->commit();
749 
750  if ($deposit && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
751  $ret = $deposit->fetch($deposit->id); // Reload to get new records
752  $outputlangs = $langs;
753 
754  if (getDolGlobalInt('MAIN_MULTILANGS')) {
755  $outputlangs = new Translate('', $conf);
756  $outputlangs->setDefaultLang($deposit->thirdparty->default_lang);
757  $outputlangs->load('products');
758  }
759 
760  $result = $deposit->generateDocument($deposit->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
761 
762  if ($result < 0) {
763  setEventMessages($deposit->error, $deposit->errors, 'errors');
764  }
765  }
766 
767  if ($locationTarget) {
768  header('Location: ' . $locationTarget);
769  exit;
770  }
771  } else {
772  $db->rollback();
773  $action = '';
774  }
775  }
776  }
777  } elseif ($action == 'confirm_reopen' && $usercanclose && !GETPOST('cancel', 'alpha')) {
778  // Reopen proposal
779  // prevent browser refresh from reopening proposal several times
780  if ($object->statut == Propal::STATUS_SIGNED || $object->statut == Propal::STATUS_NOTSIGNED || $object->statut == Propal::STATUS_BILLED) {
781  $db->begin();
782 
783  $newstatus = (getDolGlobalInt('PROPAL_SKIP_ACCEPT_REFUSE') ? Propal::STATUS_DRAFT : Propal::STATUS_VALIDATED);
784  $result = $object->reopen($user, $newstatus);
785  if ($result < 0) {
786  setEventMessages($object->error, $object->errors, 'errors');
787  $error++;
788  } else {
789  $object->statut = $newstatus;
790  $object->status = $newstatus;
791  }
792 
793  if (!$error) {
794  $db->commit();
795  } else {
796  $db->rollback();
797  }
798  }
799  } elseif ($action == 'import_lines_from_object'
800  && $user->hasRight('propal', 'creer')
801  && $object->statut == Propal::STATUS_DRAFT
802  ) {
803  // add lines from objectlinked
804  $fromElement = GETPOST('fromelement');
805  $fromElementid = GETPOST('fromelementid');
806  $importLines = GETPOST('line_checkbox');
807 
808  if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
809  if ($fromElement == 'commande') {
810  dol_include_once('/'.$fromElement.'/class/'.$fromElement.'.class.php');
811  $lineClassName = 'OrderLine';
812  } elseif ($fromElement == 'propal') {
813  dol_include_once('/comm/'.$fromElement.'/class/'.$fromElement.'.class.php');
814  $lineClassName = 'PropaleLigne';
815  } elseif ($fromElement == 'facture') {
816  dol_include_once('/compta/'.$fromElement.'/class/'.$fromElement.'.class.php');
817  $lineClassName = 'FactureLigne';
818  }
819  $nextRang = count($object->lines) + 1;
820  $importCount = 0;
821  $error = 0;
822  foreach ($importLines as $lineId) {
823  $lineId = intval($lineId);
824  $originLine = new $lineClassName($db);
825  if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
826  $originLine->fetch_optionals();
827  $desc = $originLine->desc;
828  $pu_ht = $originLine->subprice;
829  $qty = $originLine->qty;
830  $txtva = $originLine->tva_tx;
831  $txlocaltax1 = $originLine->localtax1_tx;
832  $txlocaltax2 = $originLine->localtax2_tx;
833  $fk_product = $originLine->fk_product;
834  $remise_percent = $originLine->remise_percent;
835  $date_start = $originLine->date_start;
836  $date_end = $originLine->date_end;
837  $ventil = 0;
838  $info_bits = $originLine->info_bits;
839  $fk_remise_except = $originLine->fk_remise_except;
840  $price_base_type = 'HT';
841  $pu_ttc = 0;
842  $type = $originLine->product_type;
843  $rang = $nextRang++;
844  $special_code = $originLine->special_code;
845  $origin = $originLine->element;
846  $origin_id = $originLine->id;
847  $fk_parent_line = 0;
848  $fk_fournprice = $originLine->fk_fournprice;
849  $pa_ht = $originLine->pa_ht;
850  $label = $originLine->label;
851  $array_options = $originLine->array_options;
852  $situation_percent = 100;
853  $fk_prev_id = '';
854  $fk_unit = $originLine->fk_unit;
855  $pu_ht_devise = $originLine->multicurrency_subprice;
856 
857  $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);
858 
859  if ($res > 0) {
860  $importCount++;
861  } else {
862  $error++;
863  }
864  } else {
865  $error++;
866  }
867  }
868 
869  if ($error) {
870  setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
871  }
872  }
873  }
874 
875  include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
876 
877  // Actions to send emails
878  $actiontypecode = 'AC_OTH_AUTO';
879  $triggersendname = 'PROPAL_SENTBYMAIL';
880  $autocopy = 'MAIN_MAIL_AUTOCOPY_PROPOSAL_TO';
881  $trackid = 'pro'.$object->id;
882  include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
883 
884 
885  // Go back to draft
886  if ($action == 'modif' && $usercancreate) {
887  $object->setDraft($user);
888 
889  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
890  // Define output language
891  $outputlangs = $langs;
892  if (getDolGlobalInt('MAIN_MULTILANGS')) {
893  $outputlangs = new Translate("", $conf);
894  $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
895  $outputlangs->setDefaultLang($newlang);
896  }
897  $ret = $object->fetch($id); // Reload to get new records
898  if ($ret > 0) {
899  $object->fetch_thirdparty();
900  }
901  $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
902  }
903  } elseif ($action == "setabsolutediscount" && $usercancreate) {
904  if (GETPOST("remise_id", "int")) {
905  if ($object->id > 0) {
906  $result = $object->insert_discount(GETPOST("remise_id", "int"));
907  if ($result < 0) {
908  setEventMessages($object->error, $object->errors, 'errors');
909  }
910  }
911  }
912  } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
913  // Define a vat_rate for all lines
914  $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
915  $vat_rate = str_replace('*', '', $vat_rate);
916  $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
917  $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
918  foreach ($object->lines as $line) {
919  $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);
920  }
921  } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
922  // Define a discount for all lines
923  $remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
924  $remise_percent = str_replace('*', '', $remise_percent);
925  foreach ($object->lines as $line) {
926  $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);
927  }
928  } elseif ($action == 'addline' && GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines') !== '' && $usercancreate) {
929  // Define margin
930  $margin_rate = (GETPOST('marginforalllines') ? GETPOST('marginforalllines') : 0);
931  foreach ($object->lines as &$line) {
932  $subprice = price2num($line->pa_ht * (1 + $margin_rate/100), 'MU');
933  $prod = new Product($db);
934  $prod->fetch($line->fk_product);
935  if ($prod->price_min > $subprice) {
936  $price_subprice = price($subprice, 0, $outlangs, 1, -1, -1, 'auto');
937  $price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
938  setEventMessages($prod->ref.' - '.$prod->label.' ('.$price_subprice.' < '.$price_price_min.' '.strtolower($langs->trans("MinPrice")).')'."\n", null, 'warnings');
939  }
940  // Manage $line->subprice and $line->multicurrency_subprice
941  $multicurrency_subprice = $subprice * $line->multicurrency_subprice / $line->subprice;
942  // Update DB
943  $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);
944  // Update $object with new margin info
945  $line->price = $subprice;
946  $line->marge_tx = $margin_rate;
947  $line->marque_tx = $margin_rate * $line->pa_ht / $subprice;
948  $line->total_ht = $line->qty * $subprice;
949  $line->total_tva = $line->tva_tx * $line->qty * $subprice;
950  $line->total_ttc = (1 + $line->tva_tx) * $line->qty * $subprice;
951  // Manage $line->subprice and $line->multicurrency_subprice
952  $line->multicurrency_total_ht = $line->qty * $subprice * $line->multicurrency_subprice / $line->subprice;
953  $line->multicurrency_total_tva = $line->tva_tx * $line->qty * $subprice * $line->multicurrency_subprice / $line->subprice;
954  $line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * $subprice * $line->multicurrency_subprice / $line->subprice;
955  // Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
956  $line->subprice = $subprice;
957  $line->multicurrency_subprice = $multicurrency_subprice;
958  }
959  } elseif ($action == 'addline' && $usercancreate) { // Add line
960  // Set if we used free entry or predefined product
961  $predef = '';
962  $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
963 
964  $price_ht = '';
965  $price_ht_devise = '';
966  $price_ttc = '';
967  $price_ttc_devise = '';
968 
969  // TODO Implement if (getDolGlobalInt('MAIN_UNIT_PRICE_WITH_TAX_IS_FOR_ALL_TAXES'))
970 
971  if (GETPOST('price_ht') !== '') {
972  $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
973  }
974  if (GETPOST('multicurrency_price_ht') !== '') {
975  $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
976  }
977  if (GETPOST('price_ttc') !== '') {
978  $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
979  }
980  if (GETPOST('multicurrency_price_ttc') !== '') {
981  $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
982  }
983 
984  $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
985  if ($prod_entry_mode == 'free') {
986  $idprod = 0;
987  } else {
988  $idprod = GETPOST('idprod', 'int');
989 
990  if (!empty($conf->global->MAIN_DISABLE_FREE_LINES) && $idprod <= 0) {
991  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
992  $error++;
993  }
994  }
995 
996  $tva_tx = GETPOST('tva_tx', 'alpha');
997 
998  $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
999  $remise_percent = (GETPOSTISSET('remise_percent'.$predef) ? price2num(GETPOST('remise_percent'.$predef, 'alpha'), '', 2) : 0);
1000  if (empty($remise_percent)) {
1001  $remise_percent = 0;
1002  }
1003 
1004  // Extrafields
1005  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1006  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
1007  // Unset extrafield
1008  if (is_array($extralabelsline)) {
1009  // Get extra fields
1010  foreach ($extralabelsline as $key => $value) {
1011  unset($_POST["options_".$key]);
1012  }
1013  }
1014 
1015  if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
1016  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1017  $error++;
1018  }
1019 
1020  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.
1021  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
1022  $error++;
1023  }
1024  if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($product_desc)) {
1025  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
1026  $error++;
1027  }
1028 
1029  if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
1030  if ($combinations = GETPOST('combinations', 'array')) {
1031  //Check if there is a product with the given combination
1032  $prodcomb = new ProductCombination($db);
1033 
1034  if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
1035  $idprod = $res->fk_product_child;
1036  } else {
1037  setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
1038  $error++;
1039  }
1040  }
1041  }
1042 
1043  $propal_qty_requirement = (!empty($conf->global->PROPAL_ENABLE_NEGATIVE_QTY) ? ($qty >= 0 || $qty <= 0) : $qty >= 0);
1044  if (!$error && $propal_qty_requirement && (!empty($product_desc) || (!empty($idprod) && $idprod > 0))) {
1045  $pu_ht = 0;
1046  $pu_ttc = 0;
1047  $pu_ht_devise = 0;
1048  $pu_ttc_devise = 0;
1049  $price_min = 0;
1050  $price_min_ttc = 0;
1051  $tva_npr=0;
1052  $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
1053 
1054  $db->begin();
1055 
1056  // $tva_tx can be 'x.x (XXX)'
1057 
1058  // Ecrase $pu par celui du produit
1059  // Ecrase $desc par celui du produit
1060  // Replaces $fk_unit with the product unit
1061  if (!empty($idprod) && $idprod > 0) {
1062  $prod = new Product($db);
1063  $prod->fetch($idprod);
1064 
1065  $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
1066 
1067  // Update if prices fields are defined
1068  /*$tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
1069  $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
1070  if (empty($tva_tx)) {
1071  $tva_npr = 0;
1072  }*/
1073 
1074  // Price unique per product
1075  $pu_ht = $prod->price;
1076  $pu_ttc = $prod->price_ttc;
1077  $price_min = $prod->price_min;
1078  $price_min_ttc = $prod->price_min_ttc;
1079  $price_base_type = $prod->price_base_type;
1080 
1081  // If price per segment
1082  if (!empty($conf->global->PRODUIT_MULTIPRICES) && $object->thirdparty->price_level) {
1083  $pu_ht = $prod->multiprices[$object->thirdparty->price_level];
1084  $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
1085  $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
1086  $price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
1087  $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
1088  if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility
1089  if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
1090  $tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
1091  }
1092  if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
1093  $tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
1094  }
1095  }
1096  } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
1097  // If price per customer
1098  require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
1099 
1100  $prodcustprice = new Productcustomerprice($db);
1101 
1102  $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $object->thirdparty->id);
1103 
1104  $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1105  if ($result) {
1106  // If there is some prices specific to the customer
1107  if (count($prodcustprice->lines) > 0) {
1108  $pu_ht = price($prodcustprice->lines[0]->price);
1109  $pu_ttc = price($prodcustprice->lines[0]->price_ttc);
1110  $price_min = price($prodcustprice->lines[0]->price_min);
1111  $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc);
1112  $price_base_type = $prodcustprice->lines[0]->price_base_type;
1113  /*$tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx);
1114  if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\‍(.*\‍)/', $tva_tx)) {
1115  $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')';
1116  }
1117  $tva_npr = $prodcustprice->lines[0]->recuperableonly;
1118  if (empty($tva_tx)) {
1119  $tva_npr = 0;
1120  }*/
1121  }
1122  }
1123  } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) {
1124  // If price per quantity
1125  if ($prod->prices_by_qty[0]) { // yes, this product has some prices per quantity
1126  // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1127  $pqp = GETPOST('pbq', 'int');
1128 
1129  // Search price into product_price_by_qty from $prod->id
1130  foreach ($prod->prices_by_qty_list[0] as $priceforthequantityarray) {
1131  if ($priceforthequantityarray['rowid'] != $pqp) {
1132  continue;
1133  }
1134  // We found the price
1135  if ($priceforthequantityarray['price_base_type'] == 'HT') {
1136  $pu_ht = $priceforthequantityarray['unitprice'];
1137  } else {
1138  $pu_ttc = $priceforthequantityarray['unitprice'];
1139  }
1140  // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1141  break;
1142  }
1143  }
1144  } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1145  // If price per quantity and customer
1146  if ($prod->prices_by_qty[$object->thirdparty->price_level]) { // yes, this product has some prices per quantity
1147  // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
1148  $pqp = GETPOST('pbq', 'int');
1149 
1150  // Search price into product_price_by_qty from $prod->id
1151  foreach ($prod->prices_by_qty_list[$object->thirdparty->price_level] as $priceforthequantityarray) {
1152  if ($priceforthequantityarray['rowid'] != $pqp) {
1153  continue;
1154  }
1155  // We found the price
1156  if ($priceforthequantityarray['price_base_type'] == 'HT') {
1157  $pu_ht = $priceforthequantityarray['unitprice'];
1158  } else {
1159  $pu_ttc = $priceforthequantityarray['unitprice'];
1160  }
1161  // Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
1162  break;
1163  }
1164  }
1165  }
1166 
1167  $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
1168  $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $prod->tva_tx));
1169 
1170  // Set unit price to use
1171  if (!empty($price_ht) || (string) $price_ht === '0') {
1172  $pu_ht = price2num($price_ht, 'MU');
1173  $pu_ttc = price2num($pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1174  } elseif (!empty($price_ht_devise) || (string) $price_ht_devise === '0') {
1175  $pu_ht_devise = price2num($price_ht_devise, 'MU');
1176  $pu_ht = '';
1177  $pu_ttc = '';
1178  } elseif (!empty($price_ttc) || (string) $price_ttc === '0') {
1179  $pu_ttc = price2num($price_ttc, 'MU');
1180  $pu_ht = price2num($pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1181  } elseif ($tmpvat != $tmpprodvat) {
1182  // Is this still used ?
1183  if ($price_base_type != 'HT') {
1184  $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
1185  } else {
1186  $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
1187  }
1188  }
1189 
1190  $desc = '';
1191 
1192  // Define output language
1193  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
1194  $outputlangs = $langs;
1195  $newlang = '';
1196  if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1197  $newlang = GETPOST('lang_id', 'aZ09');
1198  }
1199  if (empty($newlang)) {
1200  $newlang = $object->thirdparty->default_lang;
1201  }
1202  if (!empty($newlang)) {
1203  $outputlangs = new Translate("", $conf);
1204  $outputlangs->setDefaultLang($newlang);
1205  }
1206 
1207  $desc = (!empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description;
1208  } else {
1209  $desc = $prod->description;
1210  }
1211 
1212  //If text set in desc is the same as product description (as now it's preloaded) whe add it only one time
1213  if ($product_desc==$desc && !empty($conf->global->PRODUIT_AUTOFILL_DESC)) {
1214  $product_desc='';
1215  }
1216 
1217  if (!empty($product_desc) && !empty($conf->global->MAIN_NO_CONCAT_DESCRIPTION)) {
1218  $desc = $product_desc;
1219  } else {
1220  $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION));
1221  }
1222 
1223  // Add custom code and origin country into description
1224  if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (!empty($prod->customcode) || !empty($prod->country_code))) {
1225  $tmptxt = '(';
1226  // Define output language
1227  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
1228  $outputlangs = $langs;
1229  $newlang = '';
1230  if (empty($newlang) && GETPOST('lang_id', 'alpha')) {
1231  $newlang = GETPOST('lang_id', 'alpha');
1232  }
1233  if (empty($newlang)) {
1234  $newlang = $object->thirdparty->default_lang;
1235  }
1236  if (!empty($newlang)) {
1237  $outputlangs = new Translate("", $conf);
1238  $outputlangs->setDefaultLang($newlang);
1239  $outputlangs->load('products');
1240  }
1241  if (!empty($prod->customcode)) {
1242  $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
1243  }
1244  if (!empty($prod->customcode) && !empty($prod->country_code)) {
1245  $tmptxt .= ' - ';
1246  }
1247  if (!empty($prod->country_code)) {
1248  $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $outputlangs, 0);
1249  }
1250  } else {
1251  if (!empty($prod->customcode)) {
1252  $tmptxt .= $langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
1253  }
1254  if (!empty($prod->customcode) && !empty($prod->country_code)) {
1255  $tmptxt .= ' - ';
1256  }
1257  if (!empty($prod->country_code)) {
1258  $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $langs, 0);
1259  }
1260  }
1261  $tmptxt .= ')';
1262  $desc = dol_concatdesc($desc, $tmptxt);
1263  }
1264 
1265  $type = $prod->type;
1266  $fk_unit = $prod->fk_unit;
1267  } else {
1268  $pu_ht = price2num($price_ht, 'MU');
1269  $pu_ttc = price2num($price_ttc, 'MU');
1270  $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
1271  if (empty($tva_tx)) {
1272  $tva_npr = 0;
1273  }
1274  $tva_tx = str_replace('*', '', $tva_tx);
1275  $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1276  $desc = $product_desc;
1277  $type = GETPOST('type');
1278  $fk_unit = GETPOST('units', 'alpha');
1279  $pu_ht_devise = price2num($price_ht_devise, 'MU');
1280  $pu_ttc_devise = price2num($price_ttc_devise, 'MU');
1281 
1282  if ($pu_ttc && !$pu_ht) {
1283  $price_base_type = 'TTC';
1284  }
1285  }
1286 
1287  $info_bits = 0;
1288  if ($tva_npr) {
1289  $info_bits |= 0x01;
1290  }
1291 
1292  // Local Taxes
1293  $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $tva_npr);
1294  $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $tva_npr);
1295 
1296  // Margin
1297  $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : '');
1298  $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we muste keep this value
1299 
1300  $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'));
1301  $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'));
1302 
1303  // Prepare a price equivalent for minimum price check
1304  $pu_equivalent = $pu_ht;
1305  $pu_equivalent_ttc = $pu_ttc;
1306  $currency_tx = $object->multicurrency_tx;
1307 
1308  // Check if we have a foreign currency
1309  // If so, we update the pu_equiv as the equivalent price in base currency
1310  if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1311  $pu_equivalent = $pu_ht_devise * $currency_tx;
1312  }
1313  if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1314  $pu_equivalent_ttc = $pu_ttc_devise * $currency_tx;
1315  }
1316 
1317  // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1318  /*
1319  if ($pu_equivalent) {
1320  $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
1321  $pu_equivalent_ttc = ...
1322  } else {
1323  $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
1324  $pu_equivalent_ht = ...
1325  }
1326  */
1327 
1328  //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1329  //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1330 
1331  // Check price is not lower than minimum
1332  if ($usermustrespectpricemin) {
1333  if ($pu_equivalent && $price_min && ((price2num($pu_equivalent) * (1 - $remise_percent / 100)) < price2num($price_min)) && $price_base_type == 'HT') {
1334  $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1335  setEventMessages($mesg, null, 'errors');
1336  $error++;
1337  } elseif ($pu_equivalent_ttc && $price_min_ttc && ((price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1338  $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1339  setEventMessages($mesg, null, 'errors');
1340  $error++;
1341  }
1342  }
1343 
1344  if (!$error) {
1345  // Insert line
1346  $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);
1347 
1348  if ($result > 0) {
1349  $db->commit();
1350 
1351  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1352  // Define output language
1353  $outputlangs = $langs;
1354  if (getDolGlobalInt('MAIN_MULTILANGS')) {
1355  $outputlangs = new Translate("", $conf);
1356  $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1357  $outputlangs->setDefaultLang($newlang);
1358  }
1359  $ret = $object->fetch($id); // Reload to get new records
1360  if ($ret > 0) {
1361  $object->fetch_thirdparty();
1362  }
1363  $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1364  }
1365 
1366  unset($_POST['prod_entry_mode']);
1367 
1368  unset($_POST['qty']);
1369  unset($_POST['type']);
1370  unset($_POST['remise_percent']);
1371  unset($_POST['price_ht']);
1372  unset($_POST['multicurrency_price_ht']);
1373  unset($_POST['price_ttc']);
1374  unset($_POST['tva_tx']);
1375  unset($_POST['product_ref']);
1376  unset($_POST['product_label']);
1377  unset($_POST['product_desc']);
1378  unset($_POST['fournprice']);
1379  unset($_POST['buying_price']);
1380  unset($_POST['np_marginRate']);
1381  unset($_POST['np_markRate']);
1382  unset($_POST['dp_desc']);
1383  unset($_POST['idprod']);
1384  unset($_POST['units']);
1385 
1386  unset($_POST['date_starthour']);
1387  unset($_POST['date_startmin']);
1388  unset($_POST['date_startsec']);
1389  unset($_POST['date_startday']);
1390  unset($_POST['date_startmonth']);
1391  unset($_POST['date_startyear']);
1392  unset($_POST['date_endhour']);
1393  unset($_POST['date_endmin']);
1394  unset($_POST['date_endsec']);
1395  unset($_POST['date_endday']);
1396  unset($_POST['date_endmonth']);
1397  unset($_POST['date_endyear']);
1398  } else {
1399  $db->rollback();
1400 
1401  setEventMessages($object->error, $object->errors, 'errors');
1402  }
1403  }
1404  }
1405  } elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
1406  // Update a line within proposal
1407 
1408  // Clean parameters
1409  $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
1410 
1411  // Define info_bits
1412  $info_bits = 0;
1413  if (preg_match('/\*/', GETPOST('tva_tx'))) {
1414  $info_bits |= 0x01;
1415  }
1416 
1417  // Define vat_rate
1418  $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
1419  $vat_rate = str_replace('*', '', $vat_rate);
1420  $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
1421  $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
1422  $pu_ht = price2num(GETPOST('price_ht'), '', 2);
1423  $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
1424 
1425  // Add buying price
1426  $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
1427  $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we muste keep this value
1428 
1429  $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
1430  $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
1431 
1432  $date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
1433  $date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
1434 
1435  $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1436  if (empty($remise_percent)) {
1437  $remise_percent = 0;
1438  }
1439 
1440  // Prepare a price equivalent for minimum price check
1441  $pu_equivalent = $pu_ht;
1442  $pu_equivalent_ttc = $pu_ttc;
1443 
1444  $currency_tx = $object->multicurrency_tx;
1445 
1446  // Check if we have a foreign currency
1447  // If so, we update the pu_equiv as the equivalent price in base currency
1448  if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
1449  $pu_equivalent = $pu_ht_devise * $currency_tx;
1450  }
1451  if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
1452  $pu_equivalent_ttc = $pu_ttc_devise * $currency_tx;
1453  }
1454 
1455  // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
1456  /*
1457  if ($pu_equivalent) {
1458  $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
1459  $pu_equivalent_ttc = ...
1460  } else {
1461  $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
1462  $pu_equivalent_ht = ...
1463  }
1464  */
1465 
1466  // Extrafields
1467  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1468  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
1469  // Unset extrafield
1470  if (is_array($extralabelsline)) {
1471  // Get extra fields
1472  foreach ($extralabelsline as $key => $value) {
1473  unset($_POST["options_".$key]);
1474  }
1475  }
1476 
1477  // Define special_code for special lines
1478  $special_code = GETPOST('special_code', 'int');
1479  if (!GETPOST('qty')) {
1480  $special_code = 3;
1481  }
1482 
1483  // Check minimum price
1484  $productid = GETPOST('productid', 'int');
1485  if (!empty($productid)) {
1486  $product = new Product($db);
1487  $res = $product->fetch($productid);
1488 
1489  $type = $product->type;
1490  $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
1491 
1492  $price_min = $product->price_min;
1493  if (!empty($conf->global->PRODUIT_MULTIPRICES) && !empty($object->thirdparty->price_level)) {
1494  $price_min = $product->multiprices_min[$object->thirdparty->price_level];
1495  }
1496  $price_min_ttc = $product->price_min_ttc;
1497  if (!empty($conf->global->PRODUIT_MULTIPRICES) && !empty($object->thirdparty->price_level)) {
1498  $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
1499  }
1500 
1501  //var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
1502  //var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
1503 
1504  // Check price is not lower than minimum
1505  if ($usermustrespectpricemin) {
1506  if ($pu_equivalent && $price_min && ((price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < price2num($price_min)) && $price_base_type == 'HT') {
1507  $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1508  setEventMessages($mesg, null, 'errors');
1509  $error++;
1510  $action = 'editline';
1511  } elseif ($pu_equivalent_ttc && $price_min_ttc && ((price2num($pu_equivalent_ttc) * (1 - (float) $remise_percent / 100)) < price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1512  $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1513  setEventMessages($mesg, null, 'errors');
1514  $error++;
1515  $action = 'editline';
1516  }
1517  }
1518  } else {
1519  $type = GETPOST('type');
1520  $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1521 
1522  // Check parameters
1523  if (GETPOST('type') < 0) {
1524  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1525  $error++;
1526  }
1527  }
1528 
1529  if (!$error) {
1530  $db->begin();
1531 
1532  if (empty($user->rights->margins->creer)) {
1533  foreach ($object->lines as &$line) {
1534  if ($line->id == GETPOST('lineid', 'int')) {
1535  $fournprice = $line->fk_fournprice;
1536  $buyingprice = $line->pa_ht;
1537  break;
1538  }
1539  }
1540  }
1541 
1542  $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
1543 
1544  $pu = $pu_ht;
1545  $price_base_type = 'HT';
1546  if (empty($pu) && !empty($pu_ttc)) {
1547  $pu = $pu_ttc;
1548  $price_base_type = 'TTC';
1549  }
1550 
1551  $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);
1552 
1553  if ($result >= 0) {
1554  $db->commit();
1555 
1556  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1557  // Define output language
1558  $outputlangs = $langs;
1559  if (getDolGlobalInt('MAIN_MULTILANGS')) {
1560  $outputlangs = new Translate("", $conf);
1561  $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
1562  $outputlangs->setDefaultLang($newlang);
1563  }
1564  $ret = $object->fetch($id); // Reload to get new records
1565  if ($ret > 0) {
1566  $object->fetch_thirdparty();
1567  }
1568  $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1569  }
1570 
1571  unset($_POST['qty']);
1572  unset($_POST['type']);
1573  unset($_POST['productid']);
1574  unset($_POST['remise_percent']);
1575  unset($_POST['price_ht']);
1576  unset($_POST['multicurrency_price_ht']);
1577  unset($_POST['price_ttc']);
1578  unset($_POST['tva_tx']);
1579  unset($_POST['product_ref']);
1580  unset($_POST['product_label']);
1581  unset($_POST['product_desc']);
1582  unset($_POST['fournprice']);
1583  unset($_POST['buying_price']);
1584 
1585  unset($_POST['date_starthour']);
1586  unset($_POST['date_startmin']);
1587  unset($_POST['date_startsec']);
1588  unset($_POST['date_startday']);
1589  unset($_POST['date_startmonth']);
1590  unset($_POST['date_startyear']);
1591  unset($_POST['date_endhour']);
1592  unset($_POST['date_endmin']);
1593  unset($_POST['date_endsec']);
1594  unset($_POST['date_endday']);
1595  unset($_POST['date_endmonth']);
1596  unset($_POST['date_endyear']);
1597  } else {
1598  $db->rollback();
1599 
1600  setEventMessages($object->error, $object->errors, 'errors');
1601  }
1602  }
1603  } elseif ($action == 'updateline' && $usercancreate && GETPOST('cancel', 'alpha')) {
1604  header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // Pour reaffichage de la fiche en cours d'edition
1605  exit();
1606  } elseif ($action == 'classin' && $usercancreate) {
1607  // Set project
1608  $object->setProject(GETPOST('projectid', 'int'));
1609  } elseif ($action == 'setavailability' && $usercancreate) {
1610  // Delivery time
1611  $result = $object->set_availability($user, GETPOST('availability_id', 'int'));
1612  } elseif ($action == 'setdemandreason' && $usercancreate) {
1613  // Origin of the commercial proposal
1614  $result = $object->set_demand_reason($user, GETPOST('demand_reason_id', 'int'));
1615  } elseif ($action == 'setconditions' && $usercancreate) {
1616  // Terms of payment
1617  $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int'), GETPOST('cond_reglement_id_deposit_percent', 'alpha'));
1618  } elseif ($action == 'setremisepercent' && $usercancreate) {
1619  $result = $object->set_remise_percent($user, price2num(GETPOST('remise_percent'), '', 2));
1620  } elseif ($action == 'setremiseabsolue' && $usercancreate) {
1621  $result = $object->set_remise_absolue($user, price2num(GETPOST('remise_absolue'), 'MU', 2));
1622  } elseif ($action == 'setmode' && $usercancreate) {
1623  // Payment choice
1624  $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int'));
1625  } elseif ($action == 'setmulticurrencycode' && $usercancreate) {
1626  // Multicurrency Code
1627  $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
1628  } elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
1629  // Multicurrency rate
1630  $result = $object->setMulticurrencyRate(price2num(GETPOST('multicurrency_tx')), GETPOST('calculation_mode', 'int'));
1631  } elseif ($action == 'setbankaccount' && $usercancreate) {
1632  // bank account
1633  $result = $object->setBankAccount(GETPOST('fk_account', 'int'));
1634  } elseif ($action == 'setshippingmethod' && $usercancreate) {
1635  // shipping method
1636  $result = $object->setShippingMethod(GETPOST('shipping_method_id', 'int'));
1637  } elseif ($action == 'setwarehouse' && $usercancreate) {
1638  // warehouse
1639  $result = $object->setWarehouse(GETPOST('warehouse_id', 'int'));
1640  } elseif ($action == 'update_extras') {
1641  $object->oldcopy = dol_clone($object, 2);
1642  $attribute_name = GETPOST('attribute', 'restricthtml');
1643 
1644  // Fill array 'array_options' with data from update form
1645  $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
1646  if ($ret < 0) {
1647  $error++;
1648  }
1649  if (!$error) {
1650  $result = $object->updateExtraField($attribute_name, 'PROPAL_MODIFY');
1651  if ($result < 0) {
1652  setEventMessages($object->error, $object->errors, 'errors');
1653  $error++;
1654  }
1655  }
1656  if ($error) {
1657  $action = 'edit_extras';
1658  }
1659  }
1660 
1661  if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $usercancreate) {
1662  if ($action == 'addcontact') {
1663  if ($object->id > 0) {
1664  $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
1665  $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
1666  $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
1667  }
1668 
1669  if ($result >= 0) {
1670  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1671  exit();
1672  } else {
1673  if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1674  $langs->load("errors");
1675  setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
1676  } else {
1677  setEventMessages($object->error, $object->errors, 'errors');
1678  }
1679  }
1680  } elseif ($action == 'swapstatut') {
1681  // Toggle the status of a contact
1682  if ($object->fetch($id) > 0) {
1683  $result = $object->swapContactStatus(GETPOST('ligne', 'int'));
1684  } else {
1685  dol_print_error($db);
1686  }
1687  } elseif ($action == 'deletecontact') {
1688  // Delete a contact
1689  $object->fetch($id);
1690  $result = $object->delete_contact($lineid);
1691 
1692  if ($result >= 0) {
1693  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1694  exit();
1695  } else {
1696  dol_print_error($db);
1697  }
1698  }
1699  }
1700 
1701  // Actions to build doc
1702  $upload_dir = !empty($conf->propal->multidir_output[$object->entity])?$conf->propal->multidir_output[$object->entity]:$conf->propal->dir_output;
1703  $permissiontoadd = $usercancreate;
1704  include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
1705 }
1706 
1707 
1708 /*
1709  * View
1710  */
1711 
1712 $form = new Form($db);
1713 $formfile = new FormFile($db);
1714 $formpropal = new FormPropal($db);
1715 $formmargin = new FormMargin($db);
1716 if (isModEnabled('project')) {
1717  $formproject = new FormProjets($db);
1718 }
1719 
1720 $title = $object->ref." - ".$langs->trans('Card');
1721 if ($action == 'create') {
1722  $title = $langs->trans("NewPropal");
1723 }
1724 $help_url = 'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos|DE:Modul_Angebote';
1725 
1726 llxHeader('', $title, $help_url);
1727 
1728 $now = dol_now();
1729 
1730 // Add new proposal
1731 if ($action == 'create') {
1732  $currency_code = $conf->currency;
1733 
1734  print load_fiche_titre($langs->trans("NewProp"), '', 'propal');
1735 
1736  $soc = new Societe($db);
1737  if ($socid > 0) {
1738  $res = $soc->fetch($socid);
1739  }
1740 
1741  $currency_code = $conf->currency;
1742 
1743  $cond_reglement_id = GETPOST('cond_reglement_id', 'int');
1744  $deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'alpha');
1745  $mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1746  $fk_account = GETPOST('fk_account', 'int');
1747 
1748  // Load objectsrc
1749  if (!empty($origin) && !empty($originid)) {
1750  // Parse element/subelement (ex: project_task)
1751  $element = $subelement = $origin;
1752  $regs = array();
1753  if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
1754  $element = $regs[1];
1755  $subelement = $regs[2];
1756  }
1757 
1758  if ($element == 'project') {
1759  $projectid = $originid;
1760  } else {
1761  // For compatibility
1762  if ($element == 'order' || $element == 'commande') {
1763  $element = $subelement = 'commande';
1764  }
1765  if ($element == 'propal') {
1766  $element = 'comm/propal';
1767  $subelement = 'propal';
1768  }
1769  if ($element == 'contract') {
1770  $element = $subelement = 'contrat';
1771  }
1772  if ($element == 'shipping') {
1773  $element = $subelement = 'expedition';
1774  }
1775 
1776  dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
1777 
1778  $classname = ucfirst($subelement);
1779  $objectsrc = new $classname($db);
1780  $objectsrc->fetch($originid);
1781  if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
1782  $objectsrc->fetch_lines();
1783  }
1784  $objectsrc->fetch_thirdparty();
1785 
1786  $projectid = (!empty($objectsrc->fk_project) ? $objectsrc->fk_project : 0);
1787  $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : '');
1788 
1789  $soc = $objectsrc->thirdparty;
1790 
1791  $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
1792  $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
1793  $remise_absolue = (!empty($objectsrc->remise_absolue) ? $objectsrc->remise_absolue : (!empty($soc->remise_absolue) ? $soc->remise_absolue : 0)); // deprecated
1794  $remise_percent = (!empty($objectsrc->remise_percent) ? $objectsrc->remise_percent : (!empty($soc->remise_percent) ? $soc->remise_percent : 0));
1795  $warehouse_id = (!empty($objectsrc->warehouse_id) ? $objectsrc->warehouse_id : (!empty($soc->warehouse_id) ? $soc->warehouse_id : 0));
1796 
1797  // Replicate extrafields
1798  $objectsrc->fetch_optionals();
1799  $object->array_options = $objectsrc->array_options;
1800 
1801  if (isModEnabled("multicurrency")) {
1802  if (!empty($objectsrc->multicurrency_code)) {
1803  $currency_code = $objectsrc->multicurrency_code;
1804  }
1805  if (!empty($conf->global->MULTICURRENCY_USE_ORIGIN_TX) && !empty($objectsrc->multicurrency_tx)) {
1806  $currency_tx = $objectsrc->multicurrency_tx;
1807  }
1808  }
1809  }
1810  } else {
1811  $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
1812  $deposit_percent = empty($soc->deposit_percent) ? $deposit_percent : $soc->deposit_percent;
1813  $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
1814  $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
1815  $shipping_method_id = $soc->shipping_method_id;
1816  $warehouse_id = $soc->fk_warehouse;
1817  $remise_percent = $soc->remise_percent;
1818 
1819  if (isModEnabled("multicurrency") && !empty($soc->multicurrency_code)) {
1820  $currency_code = $soc->multicurrency_code;
1821  }
1822  }
1823 
1824  // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
1825  if (!GETPOST('changecompany')) {
1826  if (GETPOSTISSET('cond_reglement_id')) {
1827  $cond_reglement_id = GETPOST('cond_reglement_id', 'int');
1828  }
1829  if (GETPOSTISSET('deposit_percent')) {
1830  $deposit_percent = price2num(GETPOST('deposit_percent', 'alpha'));
1831  }
1832  if (GETPOSTISSET('mode_reglement_id')) {
1833  $mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1834  }
1835  if (GETPOSTISSET('cond_reglement_id')) {
1836  $fk_account = GETPOST('fk_account', 'int');
1837  }
1838  }
1839 
1840  // Warehouse default if null
1841  if ($soc->fk_warehouse > 0) {
1842  $warehouse_id = $soc->fk_warehouse;
1843  }
1844  if (isModEnabled('stock') && empty($warehouse_id) && !empty($conf->global->WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER)) {
1845  if (empty($object->warehouse_id) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE)) {
1846  $warehouse_id = $conf->global->MAIN_DEFAULT_WAREHOUSE;
1847  }
1848  if (empty($object->warehouse_id) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE_USER)) {
1849  $warehouse_id = $user->fk_warehouse;
1850  }
1851  }
1852 
1853  print '<form name="addprop" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
1854  print '<input type="hidden" name="token" value="'.newToken().'">';
1855  print '<input type="hidden" name="action" value="add">';
1856  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
1857  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
1858  if ($origin != 'project' && $originid) {
1859  print '<input type="hidden" name="origin" value="'.$origin.'">';
1860  print '<input type="hidden" name="originid" value="'.$originid.'">';
1861  } elseif ($origin == 'project' && !empty($projectid)) {
1862  print '<input type="hidden" name="projectid" value="'.$projectid.'">';
1863  }
1864 
1865  print dol_get_fiche_head();
1866 
1867  print '<table class="border centpercent">';
1868 
1869  // Reference
1870  print '<tr class="field_ref"><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td><td class="valuefieldcreate">'.$langs->trans("Draft").'</td></tr>';
1871 
1872  // Ref customer
1873  print '<tr class="field_ref_client"><td class="titlefieldcreate">'.$langs->trans('RefCustomer').'</td><td class="valuefieldcreate">';
1874  print '<input type="text" name="ref_client" value="'.(!empty($ref_client)?$ref_client:GETPOST('ref_client')).'"></td>';
1875  print '</tr>';
1876 
1877  // Third party
1878  print '<tr class="field_socid">';
1879  print '<td class="titlefieldcreate fieldrequired">'.$langs->trans('Customer').'</td>';
1880  $shipping_method_id = 0;
1881  if ($socid > 0) {
1882  print '<td class="valuefieldcreate">';
1883  print $soc->getNomUrl(1, 'customer');
1884  print '<input type="hidden" name="socid" value="'.$soc->id.'">';
1885  print '</td>';
1886  if (!empty($conf->global->SOCIETE_ASK_FOR_SHIPPING_METHOD) && !empty($soc->shipping_method_id)) {
1887  $shipping_method_id = $soc->shipping_method_id;
1888  }
1889  //$warehouse_id = $soc->warehouse_id;
1890  } else {
1891  print '<td class="valuefieldcreate">';
1892  $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
1893  print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company('', 'socid', $filter, 'SelectThirdParty', 1, 0, null, 0, 'minwidth300 maxwidth500 widthcentpercentminusxx');
1894  // reload page to retrieve customer informations
1895  if (empty($conf->global->RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED)) {
1896  print '<script>
1897  $(document).ready(function() {
1898  $("#socid").change(function() {
1899  console.log("We have changed the company - Reload page");
1900  var socid = $(this).val();
1901  // reload page
1902  $("input[name=action]").val("create");
1903  $("input[name=changecompany]").val("1");
1904  $("form[name=addprop]").submit();
1905  });
1906  });
1907  </script>';
1908  }
1909  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>';
1910  print '</td>';
1911  }
1912  print '</tr>'."\n";
1913 
1914  if ($socid > 0) {
1915  // Contacts (ask contact only if thirdparty already defined).
1916  print '<tr class="field_contactid"><td class="titlefieldcreate">'.$langs->trans("DefaultContact").'</td><td class="valuefieldcreate">';
1917  print img_picto('', 'contact', 'class="pictofixedwidth"');
1918  print $form->selectcontacts($soc->id, $contactid, 'contactid', 1, '', '', 0, 'minwidth300');
1919  print '</td></tr>';
1920 
1921  // Third party discounts info line
1922  print '<tr class="field_discount_info"><td class="titlefieldcreate">'.$langs->trans('Discounts').'</td><td class="valuefieldcreate">';
1923 
1924  $absolute_discount = $soc->getAvailableDiscounts();
1925 
1926  $thirdparty = $soc;
1927  $discount_type = 0;
1928  $backtopage = $_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.urlencode(GETPOST('origin')).'&originid='.urlencode(GETPOSTINT('originid'));
1929  include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
1930  print '</td></tr>';
1931  }
1932 
1933  // Date
1934  print '<tr class="field_addprop"><td class="titlefieldcreate fieldrequired">'.$langs->trans('DatePropal').'</td><td class="valuefieldcreate">';
1935  print img_picto('', 'action', 'class="pictofixedwidth"');
1936  print $form->selectDate('', '', '', '', '', "addprop", 1, 1);
1937  print '</td></tr>';
1938 
1939  // Validaty duration
1940  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>';
1941 
1942  // Terms of payment
1943  print '<tr class="field_cond_reglement_id"><td class="nowrap">'.$langs->trans('PaymentConditionsShort').'</td><td>';
1944  print img_picto('', 'payment', 'class="pictofixedwidth"');
1945  // at last resort we take the payment term id which may be filled by default values set (if not getpostisset)
1946  print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', 1, 1, 0, '', $deposit_percent);
1947  print '</td></tr>';
1948 
1949  // Mode of payment
1950  print '<tr class="field_mode_reglement_id"><td class="titlefieldcreate">'.$langs->trans('PaymentMode').'</td><td class="valuefieldcreate">';
1951  print img_picto('', 'bank', 'class="pictofixedwidth"');
1952  print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
1953  print '</td></tr>';
1954 
1955  // Bank Account
1956  if (!empty($conf->global->BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL) && isModEnabled("banque")) {
1957  print '<tr class="field_fk_account"><td class="titlefieldcreate">'.$langs->trans('BankAccount').'</td><td class="valuefieldcreate">';
1958  print img_picto('', 'bank_account', 'class="pictofixedwidth"').$form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
1959  print '</td></tr>';
1960  }
1961 
1962  // Source / Channel - What trigger creation
1963  print '<tr class="field_demand_reason_id"><td class="titlefieldcreate">'.$langs->trans('Source').'</td><td class="valuefieldcreate">';
1964  print img_picto('', 'question', 'class="pictofixedwidth"');
1965  $form->selectInputReason((GETPOSTISSET('demand_reason_id') ? GETPOST('demand_reason_id', 'int') : ''), 'demand_reason_id', "SRC_PROP", 1, 'maxwidth200 widthcentpercentminusx');
1966  print '</td></tr>';
1967 
1968  // Delivery delay
1969  print '<tr class="field_availability_id"><td class="titlefieldcreate">'.$langs->trans('AvailabilityPeriod');
1970  if (isModEnabled('commande')) {
1971  print ' ('.$langs->trans('AfterOrder').')';
1972  }
1973  print '</td><td class="valuefieldcreate">';
1974  print img_picto('', 'clock', 'class="pictofixedwidth"');
1975  $form->selectAvailabilityDelay((GETPOSTISSET('availability_id') ? GETPOST('availability_id', 'int') : ''), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx');
1976  print '</td></tr>';
1977 
1978  // Shipping Method
1979  if (isModEnabled("expedition")) {
1980  if (!empty($conf->global->SOCIETE_ASK_FOR_SHIPPING_METHOD) && !empty($soc->shipping_method_id)) {
1981  $shipping_method_id = $soc->shipping_method_id;
1982  }
1983  print '<tr class="field_shipping_method_id"><td class="titlefieldcreate">'.$langs->trans('SendingMethod').'</td><td class="valuefieldcreate">';
1984  print img_picto('', 'dolly', 'class="pictofixedwidth"');
1985  $form->selectShippingMethod((GETPOSTISSET('shipping_method_id') ? GETPOST('shipping_method_id', 'int') : $shipping_method_id), 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx');
1986  print '</td></tr>';
1987  }
1988 
1989  // Warehouse
1990  if (isModEnabled('stock') && !empty($conf->global->WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL)) {
1991  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
1992  $formproduct = new FormProduct($db);
1993  print '<tr class="field_warehouse_id"><td class="titlefieldcreate">'.$langs->trans('Warehouse').'</td><td class="valuefieldcreate">';
1994  print img_picto('', 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx');
1995  print '</td></tr>';
1996  }
1997 
1998  // Delivery date (or manufacturing)
1999  print '<tr class="field_date_livraison"><td class="titlefieldcreate">'.$langs->trans("DeliveryDate").'</td>';
2000  print '<td class="valuefieldcreate">';
2001  print img_picto('', 'action', 'class="pictofixedwidth"');
2002  if (isset($conf->global->DATE_LIVRAISON_WEEK_DELAY) && is_numeric($conf->global->DATE_LIVRAISON_WEEK_DELAY)) {
2003  $tmpdte = time() + ((7 * $conf->global->DATE_LIVRAISON_WEEK_DELAY) * 24 * 60 * 60);
2004  $syear = date("Y", $tmpdte);
2005  $smonth = date("m", $tmpdte);
2006  $sday = date("d", $tmpdte);
2007  print $form->selectDate($syear."-".$smonth."-".$sday, 'date_livraison', '', '', '', "addprop");
2008  } else {
2009  print $form->selectDate(-1, 'date_livraison', '', '', '', "addprop", 1, 1);
2010  }
2011  print '</td></tr>';
2012 
2013  // Project
2014  if (isModEnabled('project')) {
2015  $langs->load("projects");
2016  print '<tr class="field_projectid">';
2017  print '<td class="titlefieldcreate">'.$langs->trans("Project").'</td><td class="valuefieldcreate">';
2018  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');
2019  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>';
2020  print '</td>';
2021  print '</tr>';
2022  }
2023 
2024  // Incoterms
2025  if (isModEnabled('incoterm')) {
2026  print '<tr class="field_incoterm_id">';
2027  print '<td class="titlefieldcreate"><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $soc->label_incoterms, 1).'</label></td>';
2028  print '<td class="valuefieldcreate maxwidthonsmartphone">';
2029  print img_picto('', 'incoterm', 'class="pictofixedwidth"');
2030  print $form->select_incoterms((!empty($soc->fk_incoterms) ? $soc->fk_incoterms : ''), (!empty($soc->location_incoterms) ? $soc->location_incoterms : ''));
2031  print '</td></tr>';
2032  }
2033 
2034  // Template to use by default
2035  print '<tr class="field_model">';
2036  print '<td class="titlefieldcreate">'.$langs->trans("DefaultModel").'</td>';
2037  print '<td class="valuefieldcreate">';
2038  print img_picto('', 'pdf', 'class="pictofixedwidth"');
2039  $liste = ModelePDFPropales::liste_modeles($db);
2040  $preselected = (!empty($conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT) ? $conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT : getDolGlobalString("PROPALE_ADDON_PDF"));
2041  print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
2042  print "</td></tr>";
2043 
2044  // Multicurrency
2045  if (isModEnabled("multicurrency")) {
2046  print '<tr class="field_currency">';
2047  print '<td class="titlefieldcreate">'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
2048  print '<td class="valuefieldcreate maxwidthonsmartphone">';
2049  print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency($currency_code, 'multicurrency_code', 0);
2050  print '</td></tr>';
2051  }
2052 
2053  // Public note
2054  print '<tr class="field_note_public">';
2055  print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePublic').'</td>';
2056  print '<td class="valuefieldcreate">';
2057  $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');
2058  $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%');
2059  print $doleditor->Create(1);
2060 
2061  // Private note
2062  if (empty($user->socid)) {
2063  print '<tr class="field_note_private">';
2064  print '<td class="titlefieldcreate tdtop">'.$langs->trans('NotePrivate').'</td>';
2065  print '<td class="valuefieldcreate">';
2066  $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc)) ? $objectsrc->note_private : null));
2067  $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%');
2068  print $doleditor->Create(1);
2069  // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
2070  print '</td></tr>';
2071  }
2072 
2073  // Other attributes
2074  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
2075 
2076  // Lines from source
2077  if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2078  // TODO for compatibility
2079  if ($origin == 'contrat') {
2080  // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
2081  $objectsrc->remise_absolue = $remise_absolue; // deprecated
2082  $objectsrc->remise_percent = $remise_percent;
2083  $objectsrc->update_price(1, 'auto', 1);
2084  }
2085 
2086  print "\n<!-- ".$classname." info -->";
2087  print "\n";
2088  print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
2089  print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
2090  print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
2091  print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
2092  print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
2093 
2094  $newclassname = $classname;
2095  if ($newclassname == 'Propal') {
2096  $newclassname = 'CommercialProposal';
2097  } elseif ($newclassname == 'Commande') {
2098  $newclassname = 'Order';
2099  } elseif ($newclassname == 'Expedition') {
2100  $newclassname = 'Sending';
2101  } elseif ($newclassname == 'Fichinter') {
2102  $newclassname = 'Intervention';
2103  }
2104 
2105  print '<tr><td>'.$langs->trans($newclassname).'</td><td>'.$objectsrc->getNomUrl(1).'</td></tr>';
2106  print '<tr><td>'.$langs->trans('AmountHT').'</td><td>'.price($objectsrc->total_ht, 0, $langs, 1, -1, -1, $conf->currency).'</td></tr>';
2107  print '<tr><td>'.$langs->trans('AmountVAT').'</td><td>'.price($objectsrc->total_tva, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2108  if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
2109  print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2110  }
2111 
2112  if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
2113  print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td>'.price($objectsrc->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2114  }
2115  print '<tr><td>'.$langs->trans('AmountTTC').'</td><td>'.price($objectsrc->total_ttc, 0, $langs, 1, -1, -1, $conf->currency)."</td></tr>";
2116 
2117  if (isModEnabled("multicurrency")) {
2118  print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td>'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
2119  print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td>'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
2120  print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td>'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
2121  }
2122  }
2123 
2124  print "</table>\n";
2125 
2126 
2127  /*
2128  * Combobox for copy function
2129  */
2130 
2131  if (empty($conf->global->PROPAL_CLONE_ON_CREATE_PAGE)) {
2132  print '<input type="hidden" name="createmode" value="empty">';
2133  }
2134 
2135  if (!empty($conf->global->PROPAL_CLONE_ON_CREATE_PAGE)) {
2136  print '<br><table>';
2137 
2138  // For backward compatibility
2139  print '<tr>';
2140  print '<td><input type="radio" name="createmode" value="copy"></td>';
2141  print '<td>'.$langs->trans("CopyPropalFrom").' </td>';
2142  print '<td>';
2143  $liste_propal = array();
2144  $liste_propal [0] = '';
2145 
2146  $sql = "SELECT p.rowid as id, p.ref, s.nom";
2147  $sql .= " FROM ".MAIN_DB_PREFIX."propal p";
2148  $sql .= ", ".MAIN_DB_PREFIX."societe s";
2149  $sql .= " WHERE s.rowid = p.fk_soc";
2150  $sql .= " AND p.entity IN (".getEntity('propal').")";
2151  $sql .= " AND p.fk_statut <> 0";
2152  $sql .= " ORDER BY Id";
2153 
2154  $resql = $db->query($sql);
2155  if ($resql) {
2156  $num = $db->num_rows($resql);
2157  $i = 0;
2158  while ($i < $num) {
2159  $row = $db->fetch_row($resql);
2160  $propalRefAndSocName = $row[1]." - ".$row[2];
2161  $liste_propal[$row[0]] = $propalRefAndSocName;
2162  $i++;
2163  }
2164  print $form->selectarray("copie_propal", $liste_propal, 0);
2165  } else {
2166  dol_print_error($db);
2167  }
2168  print '</td></tr>';
2169 
2170  print '<tr><td class="tdtop"><input type="radio" name="createmode" value="empty" checked></td>';
2171  print '<td valign="top" colspan="2">'.$langs->trans("CreateEmptyPropal").'</td></tr>';
2172  print '</table>';
2173  }
2174 
2175  print dol_get_fiche_end();
2176 
2177  $langs->load("bills");
2178 
2179  print $form->buttonsSaveCancel("CreateDraft");
2180 
2181  print "</form>";
2182 
2183 
2184  // Show origin lines
2185  if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
2186  print '<br>';
2187 
2188  $title = $langs->trans('ProductsAndServices');
2189  print load_fiche_titre($title);
2190 
2191  print '<div class="div-table-responsive-no-min">';
2192  print '<table class="noborder centpercent">';
2193 
2194  $objectsrc->printOriginLinesList();
2195 
2196  print '</table>';
2197  print '</div>';
2198  }
2199 } elseif ($object->id > 0) {
2200  /*
2201  * Show object in view mode
2202  */
2203  $object->fetch_thirdparty();
2204  if ($object->thirdparty) {
2205  $soc = $object->thirdparty;
2206  } else {
2207  $soc = new Societe($db);
2208  }
2209 
2210  $head = propal_prepare_head($object);
2211  print dol_get_fiche_head($head, 'comm', $langs->trans('Proposal'), -1, 'propal');
2212 
2213  $formconfirm = '';
2214 
2215  // Clone confirmation
2216  if ($action == 'clone') {
2217  // Create an array for form
2218  $filter = '(s.client:IN:1,2,3)';
2219  $formquestion = array(
2220  // 'text' => $langs->trans("ConfirmClone"),
2221  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
2222  array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOST('socid', 'int'), 'socid', $filter, '', 0, 0, null, 0, 'maxwidth300')),
2223  array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0),
2224  array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0),
2225  );
2226  if (!empty($conf->global->PROPAL_CLONE_DATE_DELIVERY) && !empty($object->delivery_date)) {
2227  $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date);
2228  }
2229  // Incomplete payment. We ask if reason = discount or other
2230  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmClonePropal', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
2231  }
2232 
2233  if ($action == 'closeas') {
2234  //Form to close proposal (signed or not)
2235  $formquestion = array();
2236  if (empty($conf->global->PROPAL_SKIP_ACCEPT_REFUSE)) {
2237  $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)));
2238  }
2239  $formquestion[] = array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => ''); // Field to complete private note (not replace)
2240 
2241  if (getDolGlobalInt('PROPOSAL_SUGGEST_DOWN_PAYMENT_INVOICE_CREATION')) {
2242  // This is a hidden option:
2243  // Suggestion to create invoice during proposal signature is not enabled by default.
2244  // Such choice should be managed by the workflow module and trigger. This option generates conflicts with some setup.
2245  // It may also break step of creating an order when invoicing must be done from orders and not from proposal
2246  $deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
2247 
2248  if (!empty($deposit_percent_from_payment_terms) && isModEnabled('facture') && !empty($user->rights->facture->creer)) {
2249  require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
2250 
2251  $object->fetchObjectLinked();
2252 
2253  $eligibleForDepositGeneration = true;
2254 
2255  if (array_key_exists('facture', $object->linkedObjects)) {
2256  foreach ($object->linkedObjects['facture'] as $invoice) {
2257  if ($invoice->type == Facture::TYPE_DEPOSIT) {
2258  $eligibleForDepositGeneration = false;
2259  break;
2260  }
2261  }
2262  }
2263 
2264  if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) {
2265  foreach ($object->linkedObjects['commande'] as $order) {
2266  $order->fetchObjectLinked();
2267 
2268  if (array_key_exists('facture', $order->linkedObjects)) {
2269  foreach ($order->linkedObjects['facture'] as $invoice) {
2270  if ($invoice->type == Facture::TYPE_DEPOSIT) {
2271  $eligibleForDepositGeneration = false;
2272  break 2;
2273  }
2274  }
2275  }
2276  }
2277  }
2278 
2279 
2280  if ($eligibleForDepositGeneration) {
2281  $formquestion[] = array(
2282  'type' => 'checkbox',
2283  'tdclass' => 'showonlyifsigned',
2284  'name' => 'generate_deposit',
2285  'morecss' => 'margintoponly marginbottomonly',
2286  'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('DepositGenerationPermittedByThePaymentTermsSelected'))
2287  );
2288 
2289  $formquestion[] = array(
2290  'type' => 'date',
2291  'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2292  'name' => 'datef',
2293  'label' => $langs->trans('DateInvoice'),
2294  'value' => dol_now(),
2295  'datenow' => true
2296  );
2297 
2298  if (!empty($conf->global->INVOICE_POINTOFTAX_DATE)) {
2299  $formquestion[] = array(
2300  'type' => 'date',
2301  'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2302  'name' => 'date_pointoftax',
2303  'label' => $langs->trans('DatePointOfTax'),
2304  'value' => dol_now(),
2305  'datenow' => true
2306  );
2307  }
2308 
2309  $paymentTermsSelect = $form->getSelectConditionsPaiements(0, 'cond_reglement_id', -1, 0, 1, 'minwidth200');
2310 
2311  $formquestion[] = array(
2312  'type' => 'other',
2313  'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
2314  'name' => 'cond_reglement_id',
2315  'label' => $langs->trans('PaymentTerm'),
2316  'value' => $paymentTermsSelect
2317  );
2318 
2319  $formquestion[] = array(
2320  'type' => 'checkbox',
2321  'tdclass' => 'showonlyifgeneratedeposit',
2322  'name' => 'validate_generated_deposit',
2323  'morecss' => 'margintoponly marginbottomonly',
2324  'label' => $langs->trans('ValidateGeneratedDeposit')
2325  );
2326 
2327  $formquestion[] = array(
2328  'type' => 'onecolumn',
2329  'value' => '
2330  <script>
2331  let signedValue = ' . $object::STATUS_SIGNED . ';
2332 
2333  $(document).ready(function() {
2334  $("[name=generate_deposit]").change(function () {
2335  let $self = $(this);
2336  let $target = $(".showonlyifgeneratedeposit").parent(".tagtr");
2337 
2338  if (! $self.parents(".tagtr").is(":hidden") && $self.is(":checked")) {
2339  $target.show();
2340  } else {
2341  $target.hide();
2342  }
2343 
2344  return true;
2345  });
2346 
2347  $("#statut").change(function() {
2348  let $target = $(".showonlyifsigned").parent(".tagtr");
2349 
2350  if ($(this).val() == signedValue) {
2351  $target.show();
2352  } else {
2353  $target.hide();
2354  }
2355 
2356  $("[name=generate_deposit]").trigger("change");
2357 
2358  return true;
2359  });
2360 
2361  $("#statut").trigger("change");
2362  });
2363  </script>
2364  '
2365  );
2366  }
2367  }
2368  }
2369 
2370  if (isModEnabled('notification')) {
2371  require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2372  $notify = new Notify($db);
2373  $formquestion = array_merge($formquestion, array(
2374  array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)),
2375  ));
2376  }
2377 
2378  if (empty($conf->global->PROPAL_SKIP_ACCEPT_REFUSE)) {
2379  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetAcceptedRefused'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2380  } else {
2381  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?statut=3&id=' . $object->id, $langs->trans('Close'), '', 'confirm_closeas', $formquestion, '', 1, 250);
2382  }
2383  } elseif ($action == 'delete') {
2384  // Confirm delete
2385  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp', $object->ref), 'confirm_delete', '', 0, 1);
2386  } elseif ($action == 'reopen') {
2387  // Confirm reopen
2388  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp', $object->ref), 'confirm_reopen', '', 0, 1);
2389  } elseif ($action == 'ask_deleteline') {
2390  // Confirmation delete product/service line
2391  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
2392  } elseif ($action == 'validate') {
2393  // Confirm validate proposal
2394  $error = 0;
2395 
2396  // We verify whether the object is provisionally numbering
2397  $ref = substr($object->ref, 1, 4);
2398  if ($ref == 'PROV' || $ref == '') {
2399  $numref = $object->getNextNumRef($soc);
2400  if (empty($numref)) {
2401  $error++;
2402  setEventMessages($object->error, $object->errors, 'errors');
2403  }
2404  } else {
2405  $numref = $object->ref;
2406  }
2407 
2408  $text = $langs->trans('ConfirmValidateProp', $numref);
2409  if (isModEnabled('notification')) {
2410  require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
2411  $notify = new Notify($db);
2412  $text .= '<br>';
2413  $text .= $notify->confirmMessage('PROPAL_VALIDATE', $object->socid, $object);
2414  }
2415 
2416  // mandatoryPeriod
2417  $nbMandated = 0;
2418  foreach ($object->lines as $line) {
2419  $res = $line->fetch_product();
2420  if ($res > 0 ) {
2421  if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end) )) {
2422  $nbMandated++;
2423  break;
2424  }
2425  }
2426  }
2427  if ($nbMandated > 0) {
2428  $text .= '<div><span class="clearboth nowraponall warning">'.$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
2429  }
2430 
2431  if (!$error) {
2432  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateProp'), $text, 'confirm_validate', '', 0, 1);
2433  }
2434  }
2435 
2436  // Call Hook formConfirm
2437  $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
2438  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2439  if (empty($reshook)) {
2440  $formconfirm .= $hookmanager->resPrint;
2441  } elseif ($reshook > 0) {
2442  $formconfirm = $hookmanager->resPrint;
2443  }
2444 
2445  // Print form confirm
2446  print $formconfirm;
2447 
2448 
2449  // Proposal card
2450 
2451  $linkback = '<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
2452 
2453  $morehtmlref = '<div class="refidno">';
2454  // Ref customer
2455  $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
2456  $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);
2457  // Thirdparty
2458  $morehtmlref .= '<br><span class="hideonsmartphone">'.$langs->trans('ThirdParty').' : </span>'.$soc->getNomUrl(1, 'customer');
2459  if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $soc->id > 0) {
2460  $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/comm/propal/list.php?socid='.$soc->id.'&search_societe='.urlencode($soc->name).'">'.$langs->trans("OtherProposals").'</a>)';
2461  }
2462  // Project
2463  if (isModEnabled('project')) {
2464  $langs->load("projects");
2465  $morehtmlref .= '<br>';
2466  if ($usercancreate) {
2467  $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2468  if ($action != 'classify') {
2469  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
2470  }
2471  $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
2472  } else {
2473  if (!empty($object->fk_project)) {
2474  $proj = new Project($db);
2475  $proj->fetch($object->fk_project);
2476  $morehtmlref .= $proj->getNomUrl(1);
2477  if ($proj->title) {
2478  $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
2479  }
2480  }
2481  }
2482  }
2483  $morehtmlref .= '</div>';
2484 
2485 
2486  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
2487 
2488 
2489  print '<div class="fichecenter">';
2490  print '<div class="fichehalfleft">';
2491  print '<div class="underbanner clearboth"></div>';
2492 
2493  print '<table class="border tableforfield centpercent">';
2494 
2495  // Link for thirdparty discounts
2496  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
2497  $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
2498  $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
2499  } else {
2500  $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
2501  $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
2502  }
2503 
2504  print '<tr><td class="titlefield">'.$langs->trans('Discounts').'</td><td>';
2505 
2506  $absolute_discount = $soc->getAvailableDiscounts('', $filterabsolutediscount);
2507  $absolute_creditnote = $soc->getAvailableDiscounts('', $filtercreditnote);
2508  $absolute_discount = price2num($absolute_discount, 'MT');
2509  $absolute_creditnote = price2num($absolute_creditnote, 'MT');
2510 
2511  $caneditfield = ($object->statut != Propal::STATUS_SIGNED && $object->statut != Propal::STATUS_BILLED);
2512 
2513  $thirdparty = $soc;
2514  $discount_type = 0;
2515  $backtopage = $_SERVER["PHP_SELF"].'?id='.$object->id;
2516  include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
2517 
2518  print '</td></tr>';
2519 
2520  // Date of proposal
2521  print '<tr>';
2522  print '<td>';
2523  // print '<table class="nobordernopadding" width="100%"><tr><td>';
2524  // print $langs->trans('DatePropal');
2525  // print '</td>';
2526  // if ($action != 'editdate' && $usercancreate && $caneditfield) {
2527  // 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>';
2528  // }
2529 
2530  // print '</tr></table>';
2531  $editenable = $usercancreate && $caneditfield && $object->statut == Propal::STATUS_DRAFT;
2532  print $form->editfieldkey("DatePropal", 'date', '', $object, $editenable);
2533  print '</td><td class="valuefield">';
2534  if ($action == 'editdate' && $usercancreate && $caneditfield) {
2535  print '<form name="editdate" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2536  print '<input type="hidden" name="token" value="'.newToken().'">';
2537  print '<input type="hidden" name="action" value="setdate">';
2538  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2539  print $form->selectDate($object->date, 're', '', '', 0, "editdate");
2540  print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2541  print '</form>';
2542  } else {
2543  if ($object->date) {
2544  print dol_print_date($object->date, 'day');
2545  } else {
2546  print '&nbsp;';
2547  }
2548  }
2549  print '</td>';
2550 
2551  // Date end proposal
2552  print '<tr>';
2553  print '<td>';
2554  print '<table class="nobordernopadding centpercent"><tr><td>';
2555  print $langs->trans('DateEndPropal');
2556  print '</td>';
2557  if ($action != 'editecheance' && $usercancreate && $caneditfield) {
2558  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>';
2559  }
2560  print '</tr></table>';
2561  print '</td><td class="valuefield">';
2562  if ($action == 'editecheance' && $usercancreate && $caneditfield) {
2563  print '<form name="editecheance" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2564  print '<input type="hidden" name="token" value="'.newToken().'">';
2565  print '<input type="hidden" name="action" value="setecheance">';
2566  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
2567  print $form->selectDate($object->fin_validite, 'ech', '', '', '', "editecheance");
2568  print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
2569  print '</form>';
2570  } else {
2571  if (!empty($object->fin_validite)) {
2572  print dol_print_date($object->fin_validite, 'day');
2573  if ($object->statut == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) {
2574  print img_warning($langs->trans("Late"));
2575  }
2576  } else {
2577  print '&nbsp;';
2578  }
2579  }
2580  print '</td>';
2581  print '</tr>';
2582 
2583  // Payment term
2584  print '<tr><td>';
2585  print '<table class="nobordernopadding" width="100%"><tr><td>';
2586  print $langs->trans('PaymentConditionsShort');
2587  print '</td>';
2588  if ($action != 'editconditions' && $usercancreate && $caneditfield) {
2589  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>';
2590  }
2591  print '</tr></table>';
2592  print '</td><td class="valuefield">';
2593  if ($action == 'editconditions' && $usercancreate && $caneditfield) {
2594  $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 0, '', 1, $object->deposit_percent);
2595  } else {
2596  $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 0, '', 1, $object->deposit_percent);
2597  }
2598  print '</td>';
2599  print '</tr>';
2600 
2601  // Payment mode
2602  print '<tr class="field_mode_reglement_id">';
2603  print '<td class="titlefieldcreate">';
2604  print '<table class="nobordernopadding centpercent"><tr><td>';
2605  print $langs->trans('PaymentMode');
2606  print '</td>';
2607  if ($action != 'editmode' && $usercancreate && $caneditfield) {
2608  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>';
2609  }
2610  print '</tr></table>';
2611  print '</td><td class="valuefieldcreate">';
2612  if ($action == 'editmode' && $usercancreate && $caneditfield) {
2613  $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
2614  } else {
2615  $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'none');
2616  }
2617  print '</td></tr>';
2618 
2619  // Delivery date
2620  $langs->load('deliveries');
2621  print '<tr><td>';
2622  print $form->editfieldkey($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2623  print '</td><td class="valuefieldedit">';
2624  print $form->editfieldval($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
2625  print '</td>';
2626  print '</tr>';
2627 
2628  // Delivery delay
2629  print '<tr class="fielddeliverydelay"><td>';
2630  print '<table class="nobordernopadding" width="100%"><tr><td>';
2631  if (isModEnabled('commande')) {
2632  print $form->textwithpicto($langs->trans('AvailabilityPeriod'), $langs->trans('AvailabilityPeriod').' ('.$langs->trans('AfterOrder').')');
2633  } else {
2634  print $langs->trans('AvailabilityPeriod');
2635  }
2636  print '</td>';
2637  if ($action != 'editavailability' && $usercancreate && $caneditfield) {
2638  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>';
2639  }
2640  print '</tr></table>';
2641  print '</td><td class="valuefield">';
2642  if ($action == 'editavailability' && $usercancreate && $caneditfield) {
2643  $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'availability_id', 1);
2644  } else {
2645  $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'none', 1);
2646  }
2647 
2648  print '</td>';
2649  print '</tr>';
2650 
2651  // Shipping Method
2652  if (isModEnabled("expedition")) {
2653  print '<tr><td>';
2654  print '<table class="nobordernopadding centpercent"><tr><td>';
2655  print $langs->trans('SendingMethod');
2656  print '</td>';
2657  if ($action != 'editshippingmethod' && $usercancreate && $caneditfield) {
2658  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>';
2659  }
2660  print '</tr></table>';
2661  print '</td><td class="valuefield">';
2662  if ($action == 'editshippingmethod' && $usercancreate && $caneditfield) {
2663  $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1);
2664  } else {
2665  $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none');
2666  }
2667  print '</td>';
2668  print '</tr>';
2669  }
2670 
2671  // Warehouse
2672  if (isModEnabled('stock') && !empty($conf->global->WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL)) {
2673  $langs->load('stocks');
2674  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
2675  $formproduct = new FormProduct($db);
2676  print '<tr class="field_warehouse_id"><td class="titlefieldcreate">';
2677  $editenable = $usercancreate;
2678  print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable);
2679  print '</td><td class="valuefieldcreate">';
2680  if ($action == 'editwarehouse') {
2681  $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1);
2682  } else {
2683  $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'none');
2684  }
2685  print '</td>';
2686  print '</tr>';
2687  }
2688 
2689  // Origin of demand
2690  print '<tr><td>';
2691  print '<table class="nobordernopadding centpercent"><tr><td>';
2692  print $langs->trans('Source');
2693  print '</td>';
2694  if ($action != 'editdemandreason' && $usercancreate) {
2695  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>';
2696  }
2697  print '</tr></table>';
2698  print '</td><td class="valuefield">';
2699  if ($action == 'editdemandreason' && $usercancreate) {
2700  $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'demand_reason_id', 1);
2701  } else {
2702  $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'none');
2703  }
2704  print '</td>';
2705  print '</tr>';
2706 
2707  // Multicurrency
2708  if (isModEnabled("multicurrency")) {
2709  // Multicurrency code
2710  print '<tr>';
2711  print '<td>';
2712  print '<table class="nobordernopadding" width="100%"><tr><td>';
2713  print $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0);
2714  print '</td>';
2715  if ($action != 'editmulticurrencycode' && $object->statut == $object::STATUS_DRAFT && $usercancreate) {
2716  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>';
2717  }
2718  print '</tr></table>';
2719  print '</td><td class="valuefield">';
2720  if ($object->statut == $object::STATUS_DRAFT && $action == 'editmulticurrencycode' && $usercancreate) {
2721  $form->form_multicurrency_code($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_code, 'multicurrency_code');
2722  } else {
2723  $form->form_multicurrency_code($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_code, 'none');
2724  }
2725  print '</td></tr>';
2726 
2727  // Multicurrency rate
2728  if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
2729  print '<tr>';
2730  print '<td>';
2731  print '<table class="nobordernopadding" width="100%"><tr>';
2732  print '<td>';
2733  print $form->editfieldkey('CurrencyRate', 'multicurrency_tx', '', $object, 0);
2734  print '</td>';
2735  if ($action != 'editmulticurrencyrate' && $object->statut == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency && $usercancreate) {
2736  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>';
2737  }
2738  print '</tr></table>';
2739  print '</td><td class="valuefield">';
2740  if ($object->statut == $object::STATUS_DRAFT && ($action == 'editmulticurrencyrate' || $action == 'actualizemulticurrencyrate') && $usercancreate) {
2741  if ($action == 'actualizemulticurrencyrate') {
2742  list($object->fk_multicurrency, $object->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($object->db, $object->multicurrency_code);
2743  }
2744  $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, 'multicurrency_tx', $object->multicurrency_code);
2745  } else {
2746  $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, 'none', $object->multicurrency_code);
2747  if ($object->statut == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
2748  print '<div class="inline-block"> &nbsp; &nbsp; &nbsp; &nbsp; ';
2749  print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=actualizemulticurrencyrate">'.$langs->trans("ActualizeCurrency").'</a>';
2750  print '</div>';
2751  }
2752  }
2753  print '</td></tr>';
2754  }
2755  }
2756 
2757  if ($soc->outstanding_limit) {
2758  // Outstanding Bill
2759  print '<tr><td>';
2760  print $langs->trans('OutstandingBill');
2761  print '</td><td class="valuefield">';
2762  $arrayoutstandingbills = $soc->getOutstandingBills();
2763  print ($arrayoutstandingbills['opened'] > $soc->outstanding_limit ? img_warning() : '');
2764  print price($arrayoutstandingbills['opened']).' / ';
2765  print price($soc->outstanding_limit, 0, $langs, 1, - 1, - 1, $conf->currency);
2766  print '</td>';
2767  print '</tr>';
2768  }
2769 
2770  if (!empty($conf->global->BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL) && isModEnabled("banque")) {
2771  // Bank Account
2772  print '<tr><td>';
2773  print '<table width="100%" class="nobordernopadding"><tr><td>';
2774  print $langs->trans('BankAccount');
2775  print '</td>';
2776  if ($action != 'editbankaccount' && $usercancreate) {
2777  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>';
2778  }
2779  print '</tr></table>';
2780  print '</td><td class="valuefield">';
2781  if ($action == 'editbankaccount') {
2782  $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1);
2783  } else {
2784  $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none');
2785  }
2786  print '</td>';
2787  print '</tr>';
2788  }
2789 
2790  $tmparray = $object->getTotalWeightVolume();
2791  $totalWeight = $tmparray['weight'];
2792  $totalVolume = $tmparray['volume'];
2793  if ($totalWeight) {
2794  print '<tr><td>'.$langs->trans("CalculatedWeight").'</td>';
2795  print '<td class="valuefield">';
2796  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);
2797  print '</td></tr>';
2798  }
2799  if ($totalVolume) {
2800  print '<tr><td>'.$langs->trans("CalculatedVolume").'</td>';
2801  print '<td class="valuefield">';
2802  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);
2803  print '</td></tr>';
2804  }
2805 
2806  // Incoterms
2807  if (isModEnabled('incoterm')) {
2808  print '<tr><td>';
2809  print '<table width="100%" class="nobordernopadding"><tr><td>';
2810  print $langs->trans('IncotermLabel');
2811  print '<td><td class="right">';
2812  if ($action != 'editincoterm' && $usercancreate && $caneditfield) {
2813  print '<a class="editfielda" href="'.DOL_URL_ROOT.'/comm/propal/card.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
2814  } else {
2815  print '&nbsp;';
2816  }
2817  print '</td></tr></table>';
2818  print '</td>';
2819  print '<td class="valuefield">';
2820  if ($action == 'editincoterm' && $usercancreate && $caneditfield) {
2821  print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
2822  } else {
2823  print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
2824  }
2825  print '</td></tr>';
2826  }
2827 
2828  // Other attributes
2829  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2830 
2831  print '</table>';
2832 
2833  print '</div>';
2834  print '<div class="fichehalfright">';
2835  print '<div class="underbanner clearboth"></div>';
2836 
2837  print '<table class="border tableforfield centpercent">';
2838 
2839  print '<tr>';
2840  print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
2841  print '<td class="nowrap amountcard right">' . price($object->total_ht, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
2842  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2843  print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ht, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
2844  }
2845  print '</tr>';
2846 
2847  print '<tr>';
2848  print '<td class="titlefieldmiddle">' . $langs->trans('AmountVAT') . '</td>';
2849  print '<td class="nowrap amountcard right">' . price($object->total_tva, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
2850  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2851  print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_tva, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
2852  }
2853  print '</tr>';
2854 
2855  if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
2856  print '<tr>';
2857  print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
2858  print '<td class="nowrap amountcard right">' . price($object->total_localtax1, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
2859  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2860  $object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
2861 
2862  print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
2863  }
2864  print '</tr>';
2865 
2866  if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
2867  print '<tr>';
2868  print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
2869  print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
2870  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2871  $object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
2872 
2873  print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
2874  }
2875  print '</tr>';
2876  }
2877  }
2878 
2879  print '<tr>';
2880  print '<td>' . $langs->trans('AmountTTC') . '</td>';
2881  print '<td class="nowrap amountcard right">' . price($object->total_ttc, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
2882  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2883  print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ttc, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
2884  }
2885  print '</tr>';
2886 
2887  print '</table>';
2888 
2889  // Margin Infos
2890  if (isModEnabled('margin')) {
2891  $formmargin->displayMarginInfos($object);
2892  }
2893 
2894  print '</div>';
2895  print '</div>';
2896 
2897  print '<div class="clearboth"></div><br>';
2898 
2899  if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) {
2900  $blocname = 'contacts';
2901  $title = $langs->trans('ContactsAddresses');
2902  include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
2903  }
2904 
2905  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
2906  $blocname = 'notes';
2907  $title = $langs->trans('Notes');
2908  include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
2909  }
2910 
2911  /*
2912  * Lines
2913  */
2914 
2915  // Get object lines
2916  $result = $object->getLinesArray();
2917 
2918  // Add products/services form
2919  //$forceall = 1;
2920  global $inputalsopricewithtax;
2921  $inputalsopricewithtax = 1;
2922 
2923  print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
2924  <input type="hidden" name="token" value="' . newToken().'">
2925  <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
2926  <input type="hidden" name="mode" value="">
2927  <input type="hidden" name="page_y" value="">
2928  <input type="hidden" name="backtopage" value="'.$backtopage.'">
2929  <input type="hidden" name="id" value="' . $object->id.'">
2930  ';
2931 
2932  if (!empty($conf->use_javascript_ajax) && $object->statut == Propal::STATUS_DRAFT) {
2933  include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
2934  }
2935 
2936  print '<div class="div-table-responsive-no-min">';
2937  if (!empty($object->lines) || ($object->statut == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
2938  print '<table id="tablelines" class="noborder noshadow centpercent">';
2939  }
2940 
2941  if (!empty($object->lines)) {
2942  $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 1);
2943  }
2944 
2945  // Form to add new line
2946  if ($object->statut == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines') {
2947  if ($action != 'editline') {
2948  $parameters = array();
2949  $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2950  if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2951  if (empty($reshook))
2952  $object->formAddObjectLine(1, $mysoc, $soc);
2953  } else {
2954  $parameters = array();
2955  $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2956  }
2957  }
2958 
2959  if (!empty($object->lines) || ($object->statut == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
2960  print '</table>';
2961  }
2962  print '</div>';
2963 
2964  print "</form>\n";
2965 
2966  print dol_get_fiche_end();
2967 
2968 
2969  /*
2970  * Button Actions
2971  */
2972 
2973  if ($action != 'presend') {
2974  print '<div class="tabsAction">';
2975 
2976  $parameters = array();
2977  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
2978  // modified by hook
2979  if (empty($reshook)) {
2980  if ($action != 'editline') {
2981  // Validate
2982  if (($object->statut == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0)
2983  || ($object->statut == Propal::STATUS_DRAFT && !empty($conf->global->PROPAL_ENABLE_NEGATIVE) && count($object->lines) > 0)) {
2984  if ($usercanvalidate) {
2985  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>';
2986  } else {
2987  print '<a class="butActionRefused classfortooltip" href="#">'.$langs->trans('Validate').'</a>';
2988  }
2989  }
2990  // Create event
2991  /*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.
2992  {
2993  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>';
2994  }*/
2995  // Edit
2996  if ($object->statut == Propal::STATUS_VALIDATED && $usercancreate) {
2997  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=modif&token='.newToken().'">'.$langs->trans('Modify').'</a>';
2998  }
2999 
3000  // ReOpen
3001  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) {
3002  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken().(empty($conf->global->MAIN_JUMP_TAG) ? '' : '#reopen').'"';
3003  print '>'.$langs->trans('ReOpen').'</a>';
3004  }
3005 
3006  // Send
3007  if (empty($user->socid)) {
3008  if ($object->statut == Propal::STATUS_VALIDATED || $object->statut == Propal::STATUS_SIGNED || !empty($conf->global->PROPOSAL_SENDBYEMAIL_FOR_ALL_STATUS)) {
3009  print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '', $usercansend);
3010  }
3011  }
3012 
3013  // Create a sale order
3014  if (isModEnabled('commande') && $object->statut == Propal::STATUS_SIGNED) {
3015  if ($usercancreateorder) {
3016  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>';
3017  }
3018  }
3019 
3020  // Create a purchase order
3021  if (!empty($conf->global->WORKFLOW_CAN_CREATE_PURCHASE_ORDER_FROM_PROPOSAL)) {
3022  if ($object->statut == Propal::STATUS_SIGNED && isModEnabled("supplier_order")) {
3023  if ($usercancreatepurchaseorder) {
3024  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>';
3025  }
3026  }
3027  }
3028 
3029  // Create an intervention
3030  if (isModEnabled("service") && isModEnabled('ficheinter') && $object->statut == Propal::STATUS_SIGNED) {
3031  if ($usercancreateintervention) {
3032  $langs->load("interventions");
3033  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>';
3034  }
3035  }
3036 
3037  // Create contract
3038  if (isModEnabled('contrat') && $object->statut == Propal::STATUS_SIGNED) {
3039  $langs->load("contracts");
3040 
3041  if ($usercancreatecontract) {
3042  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>';
3043  }
3044  }
3045 
3046  // Create an invoice and classify billed
3047  if ($object->statut == Propal::STATUS_SIGNED && empty($conf->global->PROPOSAL_ARE_NOT_BILLABLE)) {
3048  if (isModEnabled('facture') && $usercancreateinvoice) {
3049  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>';
3050  }
3051 
3052  $arrayofinvoiceforpropal = $object->getInvoiceArrayList();
3053  if ((is_array($arrayofinvoiceforpropal) && count($arrayofinvoiceforpropal) > 0) || empty($conf->global->WORKFLOW_PROPAL_NEED_INVOICE_TO_BE_CLASSIFIED_BILLED)) {
3054  if ($usercanclose) {
3055  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=classifybilled&token='.newToken().'&socid='.$object->socid.'">'.$langs->trans("ClassifyBilled").'</a>';
3056  } else {
3057  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("ClassifyBilled").'</a>';
3058  }
3059  }
3060  }
3061 
3062  if (empty($conf->global->PROPAL_SKIP_ACCEPT_REFUSE)) {
3063  // Close as accepted/refused
3064  if ($object->statut == Propal::STATUS_VALIDATED) {
3065  if ($usercanclose) {
3066  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=closeas&token='.newToken().(empty($conf->global->MAIN_JUMP_TAG) ? '' : '#close').'"';
3067  print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3068  } else {
3069  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'"';
3070  print '>'.$langs->trans('SetAcceptedRefused').'</a>';
3071  }
3072  }
3073  } else {
3074  // Set not signed (close)
3075  if ($object->statut == Propal::STATUS_DRAFT && $usercanclose) {
3076  print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&token='.newToken().'&action=closeas&token='.newToken() . (empty($conf->global->MAIN_JUMP_TAG) ? '' : '#close') . '"';
3077  print '>' . $langs->trans('SetRefusedAndClose') . '</a>';
3078  }
3079  }
3080 
3081  // Clone
3082  if ($usercancreate) {
3083  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>';
3084  }
3085 
3086  // Delete
3087  print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $usercandelete);
3088  }
3089  }
3090 
3091  print '</div>';
3092  }
3093 
3094  //Select mail models is same action as presend
3095  if (GETPOST('modelselected')) {
3096  $action = 'presend';
3097  }
3098 
3099  if ($action != 'presend') {
3100  print '<div class="fichecenter"><div class="fichehalfleft">';
3101  print '<a name="builddoc"></a>'; // ancre
3102  /*
3103  * Generated documents
3104  */
3105  $objref = dol_sanitizeFileName($object->ref);
3106  $filedir = $conf->propal->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
3107  $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
3108  $genallowed = $usercanread;
3109  $delallowed = $usercancreate;
3110 
3111  print $formfile->showdocuments('propal', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang, '', $object);
3112 
3113  // Show links to link elements
3114  $linktoelem = $form->showLinkToObjectBlock($object, null, array('propal'));
3115 
3116  $compatibleImportElementsList = false;
3117  if ($user->rights->propal->creer && $object->statut == Propal::STATUS_DRAFT) {
3118  $compatibleImportElementsList = array('commande', 'propal', 'facture'); // import from linked elements
3119  }
3120  $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
3121 
3122  // Show online signature link
3123  $useonlinesignature = 1;
3124 
3125  if ($object->statut != Propal::STATUS_DRAFT && $useonlinesignature) {
3126  print '<br><!-- Link to sign -->';
3127  require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
3128  print showOnlineSignatureUrl('proposal', $object->ref).'<br>';
3129  }
3130 
3131  print '</div><div class="fichehalfright">';
3132 
3133  $MAXEVENT = 10;
3134 
3135  $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/comm/propal/agenda.php?id='.$object->id);
3136 
3137  // List of actions on element
3138  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
3139  $formactions = new FormActions($db);
3140  $somethingshown = $formactions->showactions($object, 'propal', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
3141 
3142  print '</div></div>';
3143  }
3144 
3145  // Presend form
3146  $modelmail = 'propal_send';
3147  $defaulttopic = 'SendPropalRef';
3148  $diroutput = $conf->propal->multidir_output[$object->entity];
3149  $trackid = 'pro'.$object->id;
3150 
3151  include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
3152 }
3153 
3154 // End of page
3155 llxFooter();
3156 $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.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
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.