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