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