dolibarr  x.y.z
card.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2019 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
6  * Copyright (C) 2010-2017 Juanjo Menent <jmenent@2byte.es>
7  * Copyright (C) 2013 Christophe Battarel <christophe.battarel@altairis.fr>
8  * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
9  * Copyright (C) 2014-2020 Ferran Marcet <fmarcet@2byte.es>
10  * Copyright (C) 2014-2016 Marcos García <marcosgdf@gmail.com>
11  * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
12  * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program. If not, see <https://www.gnu.org/licenses/>.
26  */
27 
34 require "../main.inc.php";
35 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
36 require_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/contract.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/core/modules/contract/modules_contract.php';
40 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
41 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
42 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
43 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
44 if (isModEnabled("propal")) {
45  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
46 }
47 if (isModEnabled('project')) {
48  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
49  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
50 }
51 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
52 
53 // Load translation files required by the page
54 $langs->loadLangs(array("contracts", "orders", "companies", "bills", "products", 'compta'));
55 
56 $action = GETPOST('action', 'aZ09');
57 $confirm = GETPOST('confirm', 'alpha');
58 $cancel = GETPOST('cancel', 'alpha');
59 
60 $socid = GETPOST('socid', 'int');
61 $id = GETPOST('id', 'int');
62 $ref = GETPOST('ref', 'alpha');
63 $origin = GETPOST('origin', 'alpha');
64 $originid = GETPOST('originid', 'int');
65 
66 $datecontrat = '';
67 $usehm = (!empty($conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE) ? $conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE : 0);
68 
69 // Security check
70 if ($user->socid) {
71  $socid = $user->socid;
72 }
73 $result = restrictedArea($user, 'contrat', $id);
74 
75 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
76 $hookmanager->initHooks(array('contractcard', 'globalcard'));
77 
78 $object = new Contrat($db);
79 $extrafields = new ExtraFields($db);
80 
81 // Load object
82 if ($id > 0 || !empty($ref) && $action != 'add') {
83  $ret = $object->fetch($id, $ref);
84  if ($ret > 0) {
85  $ret = $object->fetch_thirdparty();
86  }
87  if ($ret < 0) {
88  dol_print_error('', $object->error);
89  }
90 }
91 
92 // fetch optionals attributes and labels
93 $extrafields->fetch_name_optionals_label($object->table_element);
94 
95 // fetch optionals attributes lines and labels
96 $extralabelslines = $extrafields->fetch_name_optionals_label($object->table_element_line);
97 
98 $permissionnote = $user->rights->contrat->creer; // Used by the include of actions_setnotes.inc.php
99 $permissiondellink = $user->rights->contrat->creer; // Used by the include of actions_dellink.inc.php
100 $permissiontodelete = ($user->rights->contrat->creer && $object->statut == $object::STATUS_DRAFT) || $user->rights->contrat->supprimer;
101 $permissiontoadd = $user->rights->contrat->creer; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
102 $permissiontoedit = $permissiontoadd;
103 $error = 0;
104 
105 
106 /*
107  * Actions
108  */
109 
110 $parameters = array('socid' => $socid);
111 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
112 if ($reshook < 0) {
113  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
114 }
115 if (empty($reshook)) {
116  $backurlforlist = DOL_URL_ROOT.'/contrat/list.php';
117 
118  if (empty($backtopage) || ($cancel && empty($id))) {
119  if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
120  if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
121  $backtopage = $backurlforlist;
122  } else {
123  $backtopage = DOL_URL_ROOT.'/contrat/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
124  }
125  }
126  }
127 
128  if ($cancel) {
129  if (!empty($backtopageforcancel)) {
130  header("Location: ".$backtopageforcancel);
131  exit;
132  } elseif (!empty($backtopage)) {
133  header("Location: ".$backtopage);
134  exit;
135  }
136  $action = '';
137  }
138 
139  include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once
140 
141  include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once
142 
143  include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once
144 
145  if ($action == 'confirm_active' && $confirm == 'yes' && $user->rights->contrat->activer) {
146  $result = $object->active_line($user, GETPOST('ligne', 'int'), GETPOST('date'), GETPOST('dateend'), GETPOST('comment'));
147 
148  if ($result > 0) {
149  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
150  exit;
151  } else {
152  setEventMessages($object->error, $object->errors, 'errors');
153  }
154  } elseif ($action == 'confirm_closeline' && $confirm == 'yes' && $user->rights->contrat->activer) {
155  if (!GETPOST('dateend')) {
156  $error++;
157  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("DateEnd")), null, 'errors');
158  }
159  if (!$error) {
160  $result = $object->close_line($user, GETPOST('ligne', 'int'), GETPOST('dateend'), urldecode(GETPOST('comment')));
161  if ($result > 0) {
162  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
163  exit;
164  } else {
165  setEventMessages($object->error, $object->errors, 'errors');
166  }
167  }
168  }
169 
170  // Si ajout champ produit predefini
171  if (GETPOST('mode') == 'predefined') {
172  $date_start = '';
173  $date_end = '';
174  if (GETPOST('date_startmonth') && GETPOST('date_startday') && GETPOST('date_startyear')) {
175  $date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), 0, GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
176  }
177  if (GETPOST('date_endmonth') && GETPOST('date_endday') && GETPOST('date_endyear')) {
178  $date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), 0, GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
179  }
180  }
181 
182  // Param dates
183  $date_start_update = '';
184  $date_end_update = '';
185  $date_start_real_update = '';
186  $date_end_real_update = '';
187  if (GETPOST('date_start_updatemonth') && GETPOST('date_start_updateday') && GETPOST('date_start_updateyear')) {
188  $date_start_update = dol_mktime(GETPOST('date_start_updatehour'), GETPOST('date_start_updatemin'), 0, GETPOST('date_start_updatemonth'), GETPOST('date_start_updateday'), GETPOST('date_start_updateyear'));
189  }
190  if (GETPOST('date_end_updatemonth') && GETPOST('date_end_updateday') && GETPOST('date_end_updateyear')) {
191  $date_end_update = dol_mktime(GETPOST('date_end_updatehour'), GETPOST('date_end_updatemin'), 0, GETPOST('date_end_updatemonth'), GETPOST('date_end_updateday'), GETPOST('date_end_updateyear'));
192  }
193  if (GETPOST('date_start_real_updatemonth') && GETPOST('date_start_real_updateday') && GETPOST('date_start_real_updateyear')) {
194  $date_start_real_update = dol_mktime(GETPOST('date_start_real_updatehour'), GETPOST('date_start_real_updatemin'), 0, GETPOST('date_start_real_updatemonth'), GETPOST('date_start_real_updateday'), GETPOST('date_start_real_updateyear'));
195  }
196  if (GETPOST('date_end_real_updatemonth') && GETPOST('date_end_real_updateday') && GETPOST('date_end_real_updateyear')) {
197  $date_end_real_update = dol_mktime(GETPOST('date_end_real_updatehour'), GETPOST('date_end_real_updatemin'), 0, GETPOST('date_end_real_updatemonth'), GETPOST('date_end_real_updateday'), GETPOST('date_end_real_updateyear'));
198  }
199  if (GETPOST('remonth') && GETPOST('reday') && GETPOST('reyear')) {
200  $datecontrat = dol_mktime(GETPOST('rehour'), GETPOST('remin'), 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
201  }
202 
203  // Add contract
204  if ($action == 'add' && $user->rights->contrat->creer) {
205  // Check
206  if (empty($datecontrat)) {
207  $error++;
208  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
209  $action = 'create';
210  }
211 
212  if ($socid < 1) {
213  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors');
214  $action = 'create';
215  $error++;
216  }
217 
218  // Fill array 'array_options' with data from add form
219  $ret = $extrafields->setOptionalsFromPost(null, $object);
220  if ($ret < 0) {
221  $error++;
222  $action = 'create';
223  }
224 
225  if (!$error) {
226  $object->socid = $socid;
227  $object->date_contrat = $datecontrat;
228 
229  $object->commercial_suivi_id = GETPOST('commercial_suivi_id', 'int');
230  $object->commercial_signature_id = GETPOST('commercial_signature_id', 'int');
231 
232  $object->note_private = GETPOST('note_private', 'alpha');
233  $object->note_public = GETPOST('note_public', 'alpha');
234  $object->fk_project = GETPOST('projectid', 'int');
235  $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
236  $object->ref = GETPOST('ref', 'alpha');
237  $object->ref_customer = GETPOST('ref_customer', 'alpha');
238  $object->ref_supplier = GETPOST('ref_supplier', 'alpha');
239 
240  // If creation from another object of another module (Example: origin=propal, originid=1)
241  if (!empty($origin) && !empty($originid)) {
242  // Parse element/subelement (ex: project_task)
243  $element = $subelement = $origin;
244  if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
245  $element = $regs[1];
246  $subelement = $regs[2];
247  }
248 
249  // For compatibility
250  if ($element == 'order') {
251  $element = $subelement = 'commande';
252  }
253  if ($element == 'propal') {
254  $element = 'comm/propal'; $subelement = 'propal';
255  }
256  if ($element == 'invoice' || $element == 'facture') {
257  $element = 'compta/facture';
258  $subelement = 'facture';
259  }
260 
261  $object->origin = $origin;
262  $object->origin_id = $originid;
263 
264  // Possibility to add external linked objects with hooks
265  $object->linked_objects[$object->origin] = $object->origin_id;
266  if (is_array($_POST['other_linked_objects']) && !empty($_POST['other_linked_objects'])) {
267  $object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']);
268  }
269 
270  $id = $object->create($user);
271  if ($id > 0) {
272  dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
273 
274  $classname = ucfirst($subelement);
275  $srcobject = new $classname($db);
276 
277  dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines");
278  $result = $srcobject->fetch($object->origin_id);
279  if ($result > 0) {
280  $srcobject->fetch_thirdparty();
281  $lines = $srcobject->lines;
282  if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
283  $srcobject->fetch_lines();
284  $lines = $srcobject->lines;
285  }
286 
287  $fk_parent_line = 0;
288  $num = count($lines);
289 
290  for ($i = 0; $i < $num; $i++) {
291  $product_type = ($lines[$i]->product_type ? $lines[$i]->product_type : 0);
292 
293  if ($product_type == 1 || (!empty($conf->global->CONTRACT_SUPPORT_PRODUCTS) && in_array($product_type, array(0, 1)))) { // TODO Exclude also deee
294  // service prédéfini
295  if ($lines[$i]->fk_product > 0) {
296  $product_static = new Product($db);
297 
298  // Define output language
299  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
300  $prod = new Product($db);
301  $prod->id = $lines[$i]->fk_product;
302  $prod->getMultiLangs();
303 
304  $outputlangs = $langs;
305  $newlang = '';
306  if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
307  $newlang = GETPOST('lang_id', 'aZ09');
308  }
309  if (empty($newlang)) {
310  $newlang = $srcobject->thirdparty->default_lang;
311  }
312  if (!empty($newlang)) {
313  $outputlangs = new Translate("", $conf);
314  $outputlangs->setDefaultLang($newlang);
315  }
316 
317  $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["libelle"])) ? $prod->multilangs[$outputlangs->defaultlang]["libelle"] : $lines[$i]->product_label;
318  } else {
319  $label = $lines[$i]->product_label;
320  }
321  $desc = ($lines[$i]->desc && $lines[$i]->desc != $lines[$i]->libelle) ?dol_htmlentitiesbr($lines[$i]->desc) : '';
322  } else {
323  $desc = dol_htmlentitiesbr($lines[$i]->desc);
324  }
325 
326  // Extrafields
327  $array_options = array();
328  // For avoid conflicts if trigger used
329  if (method_exists($lines[$i], 'fetch_optionals')) {
330  $lines[$i]->fetch_optionals();
331  $array_options = $lines[$i]->array_options;
332  }
333 
334  $txtva = $lines[$i]->vat_src_code ? $lines[$i]->tva_tx.' ('.$lines[$i]->vat_src_code.')' : $lines[$i]->tva_tx;
335 
336  // View third's localtaxes for now
337  $localtax1_tx = get_localtax($txtva, 1, $object->thirdparty);
338  $localtax2_tx = get_localtax($txtva, 2, $object->thirdparty);
339 
340  $result = $object->addline(
341  $desc,
342  $lines[$i]->subprice,
343  $lines[$i]->qty,
344  $txtva,
345  $localtax1_tx,
346  $localtax2_tx,
347  $lines[$i]->fk_product,
348  $lines[$i]->remise_percent,
349  $lines[$i]->date_start,
350  $lines[$i]->date_end,
351  'HT',
352  0,
353  $lines[$i]->info_bits,
354  $lines[$i]->fk_fournprice,
355  $lines[$i]->pa_ht,
356  $array_options,
357  $lines[$i]->fk_unit,
358  $num+1
359  );
360 
361  if ($result < 0) {
362  $error++;
363  break;
364  }
365  }
366  }
367  } else {
368  setEventMessages($srcobject->error, $srcobject->errors, 'errors');
369  $error++;
370  }
371 
372  // Hooks
373  $parameters = array('objFrom' => $srcobject);
374  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
375  // modified by hook
376  if ($reshook < 0) {
377  $error++;
378  }
379  } else {
380  setEventMessages($object->error, $object->errors, 'errors');
381  $error++;
382  }
383  if ($error) {
384  $action = 'create';
385  }
386  } else {
387  $result = $object->create($user);
388  if ($result > 0) {
389  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
390  exit;
391  } else {
392  setEventMessages($object->error, $object->errors, 'errors');
393  }
394  $action = 'create';
395  }
396  }
397  } elseif ($action == 'classin' && $user->rights->contrat->creer) {
398  $object->setProject(GETPOST('projectid'));
399  } elseif ($action == 'addline' && $user->rights->contrat->creer) {
400  // Add a new line
401  // Set if we used free entry or predefined product
402  $predef = '';
403  $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
404 
405  $price_ht = '';
406  $price_ht_devise = '';
407  $price_ttc = '';
408  $price_ttc_devise = '';
409 
410  $rang = count($object->lines) + 1;
411 
412  if (GETPOST('price_ht') !== '') {
413  $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
414  }
415  if (GETPOST('multicurrency_price_ht') !== '') {
416  $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
417  }
418  if (GETPOST('price_ttc') !== '') {
419  $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
420  }
421  if (GETPOST('multicurrency_price_ttc') !== '') {
422  $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
423  }
424 
425  if (GETPOST('prod_entry_mode', 'alpha') == 'free') {
426  $idprod = 0;
427  } else {
428  $idprod = GETPOST('idprod', 'int');
429  }
430  $tva_tx = GETPOST('tva_tx', 'alpha');
431 
432  $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS');
433  $remise_percent = (GETPOSTISSET('remise_percent'.$predef) ? price2num(GETPOST('remise_percent'.$predef), 2) : 0);
434  if (empty($remise_percent)) {
435  $remise_percent = 0;
436  }
437 
438  if ($qty == '') {
439  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Qty")), null, 'errors');
440  $error++;
441  }
442  if (GETPOST('prod_entry_mode', 'alpha') == 'free' && (empty($idprod) || $idprod < 0) && empty($product_desc)) {
443  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
444  $error++;
445  }
446 
447  $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'));
448  $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'));
449  if (!empty($date_start) && !empty($date_end) && $date_start > $date_end) {
450  setEventMessages($langs->trans("Error").': '.$langs->trans("DateStartPlanned").' > '.$langs->trans("DateEndPlanned"), null, 'errors');
451  $error++;
452  }
453 
454  // Extrafields
455  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
456  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
457  // Unset extrafield
458  if (is_array($extralabelsline)) {
459  // Get extra fields
460  foreach ($extralabelsline as $key => $value) {
461  unset($_POST["options_".$key]);
462  }
463  }
464 
465  if (!$error) {
466  // Clean parameters
467  $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'));
468  $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'));
469 
470  // Ecrase $tva_tx par celui du produit. TODO Remove this once vat selection is open
471  // Get and check minimum price
472  if ($idprod > 0) {
473  $prod = new Product($db);
474  $prod->fetch($idprod);
475 
476  // Update if prices fields are defined
477  $tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
478  $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
479  if (empty($tva_tx)) {
480  $tva_npr = 0;
481  }
482 
483  $price_min = $prod->price_min;
484  $price_min_ttc = $prod->price_min_ttc;
485 
486  // On defini prix unitaire
487  if ($conf->global->PRODUIT_MULTIPRICES && $object->thirdparty->price_level) {
488  $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
489  $price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
490  } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
491  // If price per customer
492  require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
493 
494  $prodcustprice = new Productcustomerprice($db);
495 
496  $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $object->thirdparty->id);
497 
498  $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
499  if ($result) {
500  if (count($prodcustprice->lines) > 0) {
501  $price_min = price($prodcustprice->lines[0]->price_min);
502  $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc);
503  $tva_tx = $prodcustprice->lines[0]->tva_tx;
504  if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\‍(.*\‍)/', $tva_tx)) {
505  $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')';
506  }
507  $tva_npr = $prodcustprice->lines[0]->recuperableonly;
508  if (empty($tva_tx)) {
509  $tva_npr = 0;
510  }
511  }
512  }
513  }
514 
515  $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
516  $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $prod->tva_tx));
517 
518  // Set unit price to use
519  if (!empty($price_ht) || $price_ht === '0') {
520  $pu_ht = price2num($price_ht, 'MU');
521  $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
522  $price_base_type = 'HT';
523  } elseif (!empty($price_ttc) || $price_ttc === '0') {
524  $pu_ttc = price2num($price_ttc, 'MU');
525  $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
526  $price_base_type = 'TTC';
527  }
528 
529  $desc = $prod->description;
530 
531  //If text set in desc is the same as product descpription (as now it's preloaded) whe add it only one time
532  if ($product_desc == $desc && !empty($conf->global->PRODUIT_AUTOFILL_DESC)) {
533  $product_desc = '';
534  }
535 
536  if (!empty($product_desc) && !empty($conf->global->MAIN_NO_CONCAT_DESCRIPTION)) {
537  $desc = $product_desc;
538  } else {
539  $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION));
540  }
541 
542  $fk_unit = $prod->fk_unit;
543  } else {
544  $pu_ht = price2num($price_ht, 'MU');
545  $pu_ttc = price2num($price_ttc, 'MU');
546  $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
547  if (empty($tva_tx)) {
548  $tva_npr = 0;
549  }
550  $tva_tx = str_replace('*', '', $tva_tx);
551  $desc = $product_desc;
552  $fk_unit = GETPOST('units', 'alpha');
553  $pu_ht_devise = price2num($price_ht_devise, 'MU');
554  $pu_ttc_devise = price2num($price_ttc_devise, 'MU');
555 
556  $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
557 
558  // Set unit price to use
559  if (!empty($price_ht) || $price_ht === '0') {
560  $pu_ht = price2num($price_ht, 'MU');
561  $pu_ttc = price2num($pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
562  $price_base_type = 'HT';
563  } elseif (!empty($price_ttc) || $price_ttc === '0') {
564  $pu_ttc = price2num($price_ttc, 'MU');
565  $pu_ht = price2num($pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
566  $price_base_type = 'TTC';
567  }
568  }
569 
570  $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
571  $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
572 
573  // ajout prix achat
574  $fk_fournprice = GETPOST('fournprice');
575  if (GETPOST('buying_price')) {
576  $pa_ht = GETPOST('buying_price');
577  } else {
578  $pa_ht = null;
579  }
580 
581  $info_bits = 0;
582  if ($tva_npr) {
583  $info_bits |= 0x01;
584  }
585 
586  if (((!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->produit->ignore_price_min_advance))
587  || empty($conf->global->MAIN_USE_ADVANCED_PERMS)) && ($price_min && (price2num($pu_ht) * (1 - price2num($remise_percent) / 100) < price2num($price_min)))) {
588  $object->error = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
589  $result = -1;
590  } else {
591  // Insert line
592  $result = $object->addline(
593  $desc,
594  $pu_ht,
595  $qty,
596  $tva_tx,
597  $localtax1_tx,
598  $localtax2_tx,
599  $idprod,
600  $remise_percent,
601  $date_start,
602  $date_end,
603  $price_base_type,
604  $pu_ttc,
605  $info_bits,
606  $fk_fournprice,
607  $pa_ht,
608  $array_options,
609  $fk_unit,
610  $rang
611  );
612  }
613 
614  if ($result > 0) {
615  // Define output language
616  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE) && !empty($conf->global->CONTRACT_ADDON_PDF)) { // No generation if default type not defined
617  $outputlangs = $langs;
618  $newlang = '';
619  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
620  $newlang = GETPOST('lang_id', 'aZ09');
621  }
622  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
623  $newlang = $object->thirdparty->default_lang;
624  }
625  if (!empty($newlang)) {
626  $outputlangs = new Translate("", $conf);
627  $outputlangs->setDefaultLang($newlang);
628  }
629 
630  $ret = $object->fetch($id); // Reload to get new records
631 
632  $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
633  }
634 
635  unset($_POST['prod_entry_mode']);
636 
637  unset($_POST['qty']);
638  unset($_POST['type']);
639  unset($_POST['remise_percent']);
640  unset($_POST['price_ht']);
641  unset($_POST['multicurrency_price_ht']);
642  unset($_POST['price_ttc']);
643  unset($_POST['tva_tx']);
644  unset($_POST['product_ref']);
645  unset($_POST['product_label']);
646  unset($_POST['product_desc']);
647  unset($_POST['fournprice']);
648  unset($_POST['buying_price']);
649  unset($_POST['np_marginRate']);
650  unset($_POST['np_markRate']);
651  unset($_POST['dp_desc']);
652  unset($_POST['idprod']);
653 
654  unset($_POST['date_starthour']);
655  unset($_POST['date_startmin']);
656  unset($_POST['date_startsec']);
657  unset($_POST['date_startday']);
658  unset($_POST['date_startmonth']);
659  unset($_POST['date_startyear']);
660  unset($_POST['date_endhour']);
661  unset($_POST['date_endmin']);
662  unset($_POST['date_endsec']);
663  unset($_POST['date_endday']);
664  unset($_POST['date_endmonth']);
665  unset($_POST['date_endyear']);
666  } else {
667  setEventMessages($object->error, $object->errors, 'errors');
668  }
669  }
670  } elseif ($action == 'updateline' && $user->rights->contrat->creer && !GETPOST('cancel', 'alpha')) {
671  $error = 0;
672  $predef = '';
673 
674  if (!empty($date_start_update) && !empty($date_end_update) && $date_start_update > $date_end_update) {
675  setEventMessages($langs->trans("Error").': '.$langs->trans("DateStartPlanned").' > '.$langs->trans("DateEndPlanned"), null, 'errors');
676  $action = 'editline';
677  $_GET['rowid'] = GETPOST('elrowid');
678  $error++;
679  }
680 
681  if (!$error) {
682  $objectline = new ContratLigne($db);
683  if ($objectline->fetch(GETPOST('elrowid', 'int')) < 0) {
684  setEventMessages($objectline->error, $objectline->errors, 'errors');
685  $error++;
686  }
687  $objectline->fetch_optionals();
688 
689  $objectline->oldcopy = dol_clone($objectline);
690  }
691 
692  $db->begin();
693 
694  if (!$error) {
695  if ($date_start_real_update == '') {
696  $date_start_real_update = $objectline->date_start_real;
697  }
698  if ($date_end_real_update == '') {
699  $date_end_real_update = $objectline->date_end_real;
700  }
701 
702  $vat_rate = GETPOST('eltva_tx');
703  // Define info_bits
704  $info_bits = 0;
705  if (preg_match('/\*/', $vat_rate)) {
706  $info_bits |= 0x01;
707  }
708 
709  // Define vat_rate
710  $vat_rate = str_replace('*', '', $vat_rate);
711  $localtax1_tx = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
712  $localtax2_tx = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
713 
714  $txtva = $vat_rate;
715 
716  // Clean vat code
717  $reg = array();
718  $vat_src_code = '';
719  if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
720  $vat_src_code = $reg[1];
721  $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
722  }
723 
724  // ajout prix d'achat
725  if (GETPOST('buying_price')) {
726  $pa_ht = price2num(GETPOST('buying_price'), '', 2);
727  } else {
728  $pa_ht = null;
729  }
730 
731  $fk_unit = GETPOST('unit', 'alpha');
732 
733  $objectline->fk_product = GETPOST('idprod', 'int');
734  $objectline->description = GETPOST('product_desc', 'restricthtml');
735  $objectline->price_ht = price2num(GETPOST('elprice'), 'MU');
736  $objectline->subprice = price2num(GETPOST('elprice'), 'MU');
737  $objectline->qty = price2num(GETPOST('elqty'), 'MS');
738  $objectline->remise_percent = price2num(GETPOST('elremise_percent'), 2);
739  $objectline->tva_tx = ($txtva ? $txtva : 0); // Field may be disabled, so we use vat rate 0
740  $objectline->vat_src_code = $vat_src_code;
741  $objectline->localtax1_tx = is_numeric($localtax1_tx) ? $localtax1_tx : 0;
742  $objectline->localtax2_tx = is_numeric($localtax2_tx) ? $localtax2_tx : 0;
743  $objectline->date_start = $date_start_update;
744  $objectline->date_start_real = $date_start_real_update;
745  $objectline->date_end = $date_end_update;
746  $objectline->date_end_real = $date_end_real_update;
747  $objectline->fk_user_cloture = $user->id;
748  //$objectline->fk_fournprice = $fk_fournprice;
749  $objectline->pa_ht = $pa_ht;
750  $objectline->rang = $objectline->rang;
751 
752  if ($fk_unit > 0) {
753  $objectline->fk_unit = GETPOST('unit');
754  } else {
755  $objectline->fk_unit = null;
756  }
757 
758  // Extrafields
759  $extralabelsline = $extrafields->fetch_name_optionals_label($objectline->table_element);
760  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
761 
762  if (is_array($array_options) && count($array_options) > 0) {
763  // We replace values in this->line->array_options only for entries defined into $array_options
764  foreach ($array_options as $key => $value) {
765  $objectline->array_options[$key] = $array_options[$key];
766  }
767  }
768 
769  // TODO verifier price_min si fk_product et multiprix
770 
771  $result = $objectline->update($user);
772  if ($result < 0) {
773  $error++;
774  setEventMessages($objectline->error, $objectline->errors, 'errors');
775  }
776  }
777 
778  if (!$error) {
779  $db->commit();
780  } else {
781  $db->rollback();
782  }
783  } elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->contrat->creer) {
784  $result = $object->deleteline(GETPOST('lineid', 'int'), $user);
785 
786  if ($result >= 0) {
787  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
788  exit;
789  } else {
790  setEventMessages($object->error, $object->errors, 'errors');
791  }
792  } elseif ($action == 'confirm_valid' && $confirm == 'yes' && $user->rights->contrat->creer) {
793  $result = $object->validate($user);
794 
795  if ($result > 0) {
796  // Define output language
797  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
798  $outputlangs = $langs;
799  $newlang = '';
800  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
801  $newlang = GETPOST('lang_id', 'aZ09');
802  }
803  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
804  $newlang = $object->thirdparty->default_lang;
805  }
806  if (!empty($newlang)) {
807  $outputlangs = new Translate("", $conf);
808  $outputlangs->setDefaultLang($newlang);
809  }
810  $model = $object->model_pdf;
811  $ret = $object->fetch($id); // Reload to get new records
812 
813  $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
814  }
815  } else {
816  setEventMessages($object->error, $object->errors, 'errors');
817  }
818  } elseif ($action == 'reopen' && $user->rights->contrat->creer) {
819  $result = $object->reopen($user);
820  if ($result < 0) {
821  setEventMessages($object->error, $object->errors, 'errors');
822  }
823  } elseif ($action == 'confirm_close' && $confirm == 'yes' && $user->rights->contrat->creer) {
824  // Close all lines
825  $result = $object->closeAll($user);
826  if ($result < 0) {
827  setEventMessages($object->error, $object->errors, 'errors');
828  }
829  } elseif ($action == 'confirm_activate' && $confirm == 'yes' && $user->rights->contrat->creer) {
830  $date_start = dol_mktime(12, 0, 0, GETPOST('d_startmonth'), GETPOST('d_startday'), GETPOST('d_startyear'));
831  $date_end = dol_mktime(12, 0, 0, GETPOST('d_endmonth'), GETPOST('d_endday'), GETPOST('d_endyear'));
832  $comment = GETPOST('comment', 'alpha');
833  $result = $object->activateAll($user, $date_start, 0, $comment, $date_end);
834  if ($result < 0) {
835  setEventMessages($object->error, $object->errors, 'errors');
836  }
837  } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->contrat->supprimer) {
838  $result = $object->delete($user);
839  if ($result >= 0) {
840  header("Location: list.php?restore_lastsearch_values=1");
841  return;
842  } else {
843  setEventMessages($object->error, $object->errors, 'errors');
844  }
845  } elseif ($action == 'confirm_move' && $confirm == 'yes' && $user->rights->contrat->creer) {
846  if (GETPOST('newcid') > 0) {
847  $contractline = new ContratLigne($db);
848  $result = $contractline->fetch(GETPOSTINT('lineid'));
849  $contractline->fk_contrat = GETPOSTINT('newcid');
850  $result = $contractline->update($user, 1);
851  if ($result >= 0) {
852  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
853  return;
854  } else {
855  setEventMessages($object->error, $object->errors, 'errors');
856  }
857  } else {
858  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("RefNewContract")), null, 'errors');
859  }
860  } elseif ($action == 'update_extras') {
861  $object->oldcopy = dol_clone($object);
862 
863  // Fill array 'array_options' with data from update form
864  $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
865  if ($ret < 0) {
866  $error++;
867  }
868 
869  if (!$error) {
870  $result = $object->insertExtraFields('CONTRACT_MODIFY');
871  if ($result < 0) {
872  setEventMessages($object->error, $object->errors, 'errors');
873  $error++;
874  }
875  }
876 
877  if ($error) {
878  $action = 'edit_extras';
879  }
880  } elseif ($action == 'setref_supplier') {
881  if (!$cancel) {
882  $object->oldcopy = dol_clone($object);
883 
884  $result = $object->setValueFrom('ref_supplier', GETPOST('ref_supplier', 'alpha'), '', null, 'text', '', $user, 'CONTRACT_MODIFY');
885  if ($result < 0) {
886  setEventMessages($object->error, $object->errors, 'errors');
887  $action = 'editref_supplier';
888  } else {
889  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
890  exit;
891  }
892  } else {
893  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
894  exit;
895  }
896  } elseif ($action == 'setref_customer') {
897  if (!$cancel) {
898  $object->oldcopy = dol_clone($object);
899 
900  $result = $object->setValueFrom('ref_customer', GETPOST('ref_customer', 'alpha'), '', null, 'text', '', $user, 'CONTRACT_MODIFY');
901  if ($result < 0) {
902  setEventMessages($object->error, $object->errors, 'errors');
903  $action = 'editref_customer';
904  } else {
905  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
906  exit;
907  }
908  } else {
909  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
910  exit;
911  }
912  } elseif ($action == 'setref') {
913  if (!$cancel) {
914  $result = $object->fetch($id);
915  if ($result < 0) {
916  setEventMessages($object->error, $object->errors, 'errors');
917  }
918 
919  $old_ref = $object->ref;
920 
921  $result = $object->setValueFrom('ref', GETPOST('ref', 'alpha'), '', null, 'text', '', $user, 'CONTRACT_MODIFY');
922  if ($result < 0) {
923  setEventMessages($object->error, $object->errors, 'errors');
924  $action = 'editref';
925  } else {
926  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
927  $old_filedir = $conf->contrat->multidir_output[$object->entity].'/'.dol_sanitizeFileName($old_ref);
928  $new_filedir = $conf->contrat->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
929 
930  $files = dol_dir_list($old_filedir);
931  if (!empty($files)) {
932  if (!is_dir($new_filedir)) {
933  dol_mkdir($new_filedir);
934  }
935  foreach ($files as $file) {
936  dol_move($file['fullname'], $new_filedir.'/'.$file['name']);
937  }
938  }
939 
940  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
941  exit;
942  }
943  } else {
944  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
945  exit;
946  }
947  } elseif ($action == 'setdate_contrat') {
948  if (!$cancel) {
949  $result = $object->fetch($id);
950  if ($result < 0) {
951  setEventMessages($object->error, $object->errors, 'errors');
952  }
953  $datacontrat = dol_mktime(GETPOST('date_contrathour'), GETPOST('date_contratmin'), 0, GETPOST('date_contratmonth'), GETPOST('date_contratday'), GETPOST('date_contratyear'));
954  $result = $object->setValueFrom('date_contrat', $datacontrat, '', null, 'date', '', $user, 'CONTRACT_MODIFY');
955  if ($result < 0) {
956  setEventMessages($object->error, $object->errors, 'errors');
957  $action = 'editdate_contrat';
958  } else {
959  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
960  exit;
961  }
962  } else {
963  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
964  exit;
965  }
966  }
967 
968  // Actions when printing a doc from card
969  include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
970 
971  // Actions to build doc
972  $upload_dir = $conf->contrat->multidir_output[$object->entity];
973  include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
974 
975  // Actions to send emails
976  $triggersendname = 'CONTRACT_SENTBYMAIL';
977  $paramname = 'id';
978  $mode = 'emailfromcontract';
979  $trackid = 'con'.$object->id;
980  include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
981 
982 
983  if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->contrat->creer) {
984  if ($action == 'addcontact') {
985  $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
986  $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
987  $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
988 
989  if ($result >= 0) {
990  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
991  exit;
992  } else {
993  if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
994  $langs->load("errors");
995  setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
996  } else {
997  setEventMessages($object->error, $object->errors, 'errors');
998  }
999  }
1000  } elseif ($action == 'swapstatut') {
1001  // bascule du statut d'un contact
1002  $result = $object->swapContactStatus(GETPOST('ligne', 'int'));
1003  } elseif ($action == 'deletecontact') {
1004  // Efface un contact
1005  $result = $object->delete_contact(GETPOST('lineid', 'int'));
1006 
1007  if ($result >= 0) {
1008  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
1009  exit;
1010  } else {
1011  setEventMessages($object->error, $object->errors, 'errors');
1012  }
1013  }
1014  }
1015 
1016  // Action clone object
1017  if ($action == 'confirm_clone' && $confirm == 'yes') {
1018  if (!GETPOST('socid', 3)) {
1019  setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
1020  } else {
1021  if ($object->id > 0) {
1022  $result = $object->createFromClone($user, $socid);
1023  if ($result > 0) {
1024  header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result);
1025  exit();
1026  } else {
1027  if (count($object->errors) > 0) {
1028  setEventMessages($object->error, $object->errors, 'errors');
1029  }
1030  $action = '';
1031  }
1032  }
1033  }
1034  }
1035 }
1036 
1037 
1038 /*
1039  * View
1040  */
1041 
1042 
1043 $help_url = 'EN:Module_Contracts|FR:Module_Contrat';
1044 
1045 llxHeader('', $langs->trans("Contract"), $help_url);
1046 
1047 $form = new Form($db);
1048 $formfile = new FormFile($db);
1049 if (isModEnabled('project')) {
1050  $formproject = new FormProjets($db);
1051 }
1052 
1053 // Load object modContract
1054 $module = (!empty($conf->global->CONTRACT_ADDON) ? $conf->global->CONTRACT_ADDON : 'mod_contract_serpis');
1055 if (substr($module, 0, 13) == 'mod_contract_' && substr($module, -3) == 'php') {
1056  $module = substr($module, 0, dol_strlen($module) - 4);
1057 }
1058 $result = dol_include_once('/core/modules/contract/'.$module.'.php');
1059 if ($result > 0) {
1060  $modCodeContract = new $module();
1061 }
1062 
1063 // Create
1064 if ($action == 'create') {
1065  print load_fiche_titre($langs->trans('AddContract'), '', 'contract');
1066 
1067  $soc = new Societe($db);
1068  if ($socid > 0) {
1069  $soc->fetch($socid);
1070  }
1071 
1072  if (GETPOST('origin') && GETPOST('originid', 'int')) {
1073  // Parse element/subelement (ex: project_task)
1074  $regs = array();
1075  $element = $subelement = GETPOST('origin');
1076  if (preg_match('/^([^_]+)_([^_]+)/i', GETPOST('origin'), $regs)) {
1077  $element = $regs[1];
1078  $subelement = $regs[2];
1079  }
1080 
1081  if ($element == 'project') {
1082  $projectid = GETPOST('originid', 'int');
1083  } else {
1084  // For compatibility
1085  if ($element == 'order' || $element == 'commande') {
1086  $element = $subelement = 'commande';
1087  }
1088  if ($element == 'propal') {
1089  $element = 'comm/propal'; $subelement = 'propal';
1090  }
1091  if ($element == 'invoice' || $element == 'facture') {
1092  $element = 'compta/facture';
1093  $subelement = 'facture';
1094  }
1095 
1096  dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
1097 
1098  $classname = ucfirst($subelement);
1099  $objectsrc = new $classname($db);
1100  $objectsrc->fetch($originid);
1101  if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
1102  $objectsrc->fetch_lines();
1103  }
1104  $objectsrc->fetch_thirdparty();
1105 
1106  // Replicate extrafields
1107  $objectsrc->fetch_optionals();
1108  $object->array_options = $objectsrc->array_options;
1109 
1110  $projectid = (!empty($objectsrc->fk_project) ? $objectsrc->fk_project : '');
1111 
1112  $soc = $objectsrc->thirdparty;
1113 
1114  $note_private = (!empty($objectsrc->note_private) ? $objectsrc->note_private : '');
1115  $note_public = (!empty($objectsrc->note_public) ? $objectsrc->note_public : '');
1116 
1117  // Object source contacts list
1118  $srccontactslist = $objectsrc->liste_contact(-1, 'external', 1);
1119  }
1120  } else {
1121  $projectid = GETPOST('projectid', 'int');
1122  $note_private = GETPOST("note_private");
1123  $note_public = GETPOST("note_public");
1124  }
1125 
1126  $object->date_contrat = dol_now();
1127 
1128  print '<form name="form_contract" action="'.$_SERVER["PHP_SELF"].'" method="post">';
1129  print '<input type="hidden" name="token" value="'.newToken().'">';
1130 
1131  print '<input type="hidden" name="action" value="add">';
1132  print '<input type="hidden" name="socid" value="'.$soc->id.'">'."\n";
1133  print '<input type="hidden" name="remise_percent" value="0">';
1134 
1135  print dol_get_fiche_head();
1136 
1137  print '<table class="border centpercent">';
1138 
1139  // Ref
1140  print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td><td>';
1141  if (!empty($modCodeContract->code_auto)) {
1142  $tmpcode = $langs->trans("Draft");
1143  } else {
1144  $tmpcode = '<input name="ref" class="maxwidth100" maxlength="128" value="'.dol_escape_htmltag(GETPOST('ref') ?GETPOST('ref') : $tmpcode).'">';
1145  }
1146  print $tmpcode;
1147  print '</td></tr>';
1148 
1149  // Ref customer
1150  print '<tr><td>'.$langs->trans('RefCustomer').'</td>';
1151  print '<td><input type="text" class="maxwidth150" name="ref_customer" id="ref_customer" value="'.dol_escape_htmltag(GETPOST('ref_customer', 'alpha')).'"></td></tr>';
1152 
1153  // Ref supplier
1154  print '<tr><td>'.$langs->trans('RefSupplier').'</td>';
1155  print '<td><input type="text" class="maxwidth150" name="ref_supplier" id="ref_supplier" value="'.dol_escape_htmltag(GETPOST('ref_supplier', 'alpha')).'"></td></tr>';
1156 
1157  // Thirdparty
1158  print '<tr>';
1159  print '<td class="fieldrequired">'.$langs->trans('ThirdParty').'</td>';
1160  if ($socid > 0) {
1161  print '<td>';
1162  print $soc->getNomUrl(1);
1163  print '<input type="hidden" name="socid" value="'.$soc->id.'">';
1164  print '</td>';
1165  } else {
1166  print '<td>';
1167  print img_picto('', 'company', 'class="pictofixedwidth"');
1168  print $form->select_company('', 'socid', '', 'SelectThirdParty', 1, 0, null, 0, 'minwidth300 widthcentpercentminusxx maxwidth500');
1169  print ' <a href="'.DOL_URL_ROOT.'/societe/card.php?action=create&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create').'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddThirdParty").'"></span></a>';
1170  print '</td>';
1171  }
1172  print '</tr>'."\n";
1173 
1174  if ($socid > 0) {
1175  // Ligne info remises tiers
1176  print '<tr><td>'.$langs->trans('Discounts').'</td><td>';
1177  if ($soc->remise_percent) {
1178  print $langs->trans("CompanyHasRelativeDiscount", $soc->remise_percent).' ';
1179  } else {
1180  print '<span class="hideonsmartphone">'.$langs->trans("CompanyHasNoRelativeDiscount").'. </span>';
1181  }
1182  $absolute_discount = $soc->getAvailableDiscounts();
1183  if ($absolute_discount) {
1184  print $langs->trans("CompanyHasAbsoluteDiscount", price($absolute_discount), $langs->trans("Currency".$conf->currency)).'.';
1185  } else {
1186  print '<span class="hideonsmartphone">'.$langs->trans("CompanyHasNoAbsoluteDiscount").'.</span>';
1187  }
1188  print '</td></tr>';
1189  }
1190 
1191  // Commercial suivi
1192  print '<tr><td class="nowrap"><span class="fieldrequired">'.$langs->trans("TypeContact_contrat_internal_SALESREPFOLL").'</span></td><td>';
1193  print img_picto('', 'user', 'class="pictofixedwidth"');
1194  print $form->select_dolusers(GETPOST("commercial_suivi_id") ?GETPOST("commercial_suivi_id") : $user->id, 'commercial_suivi_id', 1, '');
1195  print '</td></tr>';
1196 
1197  // Commercial signature
1198  print '<tr><td class="nowrap"><span class="fieldrequired">'.$langs->trans("TypeContact_contrat_internal_SALESREPSIGN").'</span></td><td>';
1199  print img_picto('', 'user', 'class="pictofixedwidth"');
1200  print $form->select_dolusers(GETPOST("commercial_signature_id") ?GETPOST("commercial_signature_id") : $user->id, 'commercial_signature_id', 1, '');
1201  print '</td></tr>';
1202 
1203  print '<tr><td><span class="fieldrequired">'.$langs->trans("Date").'</span></td><td>';
1204  print $form->selectDate($datecontrat, '', 0, 0, '', "contrat");
1205  print "</td></tr>";
1206 
1207  // Project
1208  if (isModEnabled('project')) {
1209  $langs->load('projects');
1210 
1211  $formproject = new FormProjets($db);
1212 
1213  print '<tr><td>'.$langs->trans("Project").'</td><td>';
1214  $formproject->select_projects(($soc->id > 0 ? $soc->id : -1), $projectid, "projectid", 0, 0, 1, 1);
1215  print ' &nbsp; <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" title="'.$langs->trans("AddProject").'"></span></a>';
1216  print "</td></tr>";
1217  }
1218 
1219  print '<tr><td>'.$langs->trans("NotePublic").'</td><td class="tdtop">';
1220  $doleditor = new DolEditor('note_public', $note_public, '', '100', 'dolibarr_notes', 'In', 1, true, empty($conf->global->FCKEDITOR_ENABLE_NOTE_PUBLIC) ? 0 : 1, ROWS_3, '90%');
1221  print $doleditor->Create(1);
1222  print '</td></tr>';
1223 
1224  if (empty($user->socid)) {
1225  print '<tr><td>'.$langs->trans("NotePrivate").'</td><td class="tdtop">';
1226  $doleditor = new DolEditor('note_private', $note_private, '', '100', 'dolibarr_notes', 'In', 1, true, empty($conf->global->FCKEDITOR_ENABLE_NOTE_PRIVATE) ? 0 : 1, ROWS_3, '90%');
1227  print $doleditor->Create(1);
1228  print '</td></tr>';
1229  }
1230 
1231  // Other attributes
1232  $parameters = array('objectsrc' => $objectsrc, 'colspan' => ' colspan="3"', 'cols' => '3');
1233  $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1234  print $hookmanager->resPrint;
1235 
1236  // Other attributes
1237  if (empty($reshook)) {
1238  print $object->showOptionals($extrafields, 'create', $parameters);
1239  }
1240 
1241  print "</table>\n";
1242 
1243  print dol_get_fiche_end();
1244 
1245  print $form->buttonsSaveCancel("Create");
1246 
1247  if (is_object($objectsrc)) {
1248  print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
1249  print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
1250 
1251  if (empty($conf->global->CONTRACT_SUPPORT_PRODUCTS)) {
1252  print '<br>'.$langs->trans("Note").': '.$langs->trans("OnlyLinesWithTypeServiceAreUsed");
1253  }
1254  }
1255 
1256  print "</form>\n";
1257 } else {
1258  // View and edit mode
1259  $now = dol_now();
1260 
1261  if ($object->id > 0) {
1262  $object->fetch_thirdparty();
1263 
1264  $soc = $object->thirdparty; // $soc is used later
1265 
1266  $result = $object->fetch_lines(); // This also init $this->nbofserviceswait, $this->nbofservicesopened, $this->nbofservicesexpired=, $this->nbofservicesclosed
1267  if ($result < 0) {
1268  dol_print_error($db, $object->error);
1269  }
1270 
1271  $nbofservices = count($object->lines);
1272 
1273  $author = new User($db);
1274  $author->fetch($object->user_author_id);
1275 
1276  $commercial_signature = new User($db);
1277  $commercial_signature->fetch($object->commercial_signature_id);
1278 
1279  $commercial_suivi = new User($db);
1280  $commercial_suivi->fetch($object->commercial_suivi_id);
1281 
1282  $head = contract_prepare_head($object);
1283 
1284  $hselected = 0;
1285  $formconfirm = '';
1286 
1287  print dol_get_fiche_head($head, $hselected, $langs->trans("Contract"), -1, 'contract');
1288 
1289 
1290  if ($action == 'delete') {
1291  //Confirmation de la suppression du contrat
1292  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF']."?id=".$object->id, $langs->trans("DeleteAContract"), $langs->trans("ConfirmDeleteAContract"), "confirm_delete", '', 0, 1);
1293  } elseif ($action == 'valid') {
1294  //Confirmation de la validation
1295  $ref = substr($object->ref, 1, 4);
1296  if ($ref == 'PROV' && !empty($modCodeContract->code_auto)) {
1297  $numref = $object->getNextNumRef($object->thirdparty);
1298  } else {
1299  $numref = $object->ref;
1300  }
1301  $text = $langs->trans('ConfirmValidateContract', $numref);
1302  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF']."?id=".$object->id, $langs->trans("ValidateAContract"), $text, "confirm_valid", '', 0, 1);
1303  } elseif ($action == 'close') {
1304  // Confirmation de la fermeture
1305  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF']."?id=".$object->id, $langs->trans("CloseAContract"), $langs->trans("ConfirmCloseContract"), "confirm_close", '', 0, 1);
1306  } elseif ($action == 'activate') {
1307  $formquestion = array(
1308  array('type' => 'date', 'name' => 'd_start', 'label' => $langs->trans("DateServiceActivate"), 'value' => dol_now()),
1309  array('type' => 'date', 'name' => 'd_end', 'label' => $langs->trans("DateEndPlanned"), /*'value' => $form->selectDate('', "end", $usehm, $usehm, '', "active", 1, 0),*/ '', ''),
1310  array('type' => 'text', 'name' => 'comment', 'label' => $langs->trans("Comment"), 'value' => '', '', '', 'class' => 'minwidth300', 'moreattr'=>'autofocus')
1311  );
1312  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF']."?id=".$object->id, $langs->trans("ActivateAllOnContract"), $langs->trans("ConfirmActivateAllOnContract"), "confirm_activate", $formquestion, 'yes', 1, 280);
1313  } elseif ($action == 'clone') {
1314  // Clone confirmation
1315  $formquestion = array(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)')));
1316  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneContract', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
1317  }
1318 
1319 
1320  // Call Hook formConfirm
1321  $parameters = array(
1322  'formConfirm' => $formconfirm,
1323  'id' => $id,
1324  //'lineid' => $lineid,
1325  );
1326  // Note that $action and $object may have been modified by hook
1327  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
1328  if (empty($reshook)) {
1329  $formconfirm .= $hookmanager->resPrint;
1330  } elseif ($reshook > 0) {
1331  $formconfirm = $hookmanager->resPrint;
1332  }
1333 
1334  // Print form confirm
1335  print $formconfirm;
1336 
1337 
1338  // Contract
1339  if (!empty($object->brouillon) && $user->rights->contrat->creer) {
1340  print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="POST">';
1341  print '<input type="hidden" name="token" value="'.newToken().'">';
1342  print '<input type="hidden" name="action" value="setremise">';
1343  }
1344 
1345  // Contract card
1346 
1347  $linkback = '<a href="'.DOL_URL_ROOT.'/contrat/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
1348 
1349 
1350  $morehtmlref = '';
1351  if (!empty($modCodeContract->code_auto)) {
1352  $morehtmlref .= $object->ref;
1353  } else {
1354  $morehtmlref .= $form->editfieldkey("", 'ref', $object->ref, $object, $user->rights->contrat->creer, 'string', '', 0, 3);
1355  $morehtmlref .= $form->editfieldval("", 'ref', $object->ref, $object, $user->rights->contrat->creer, 'string', '', 0, 2);
1356  }
1357 
1358  $morehtmlref .= '<div class="refidno">';
1359  // Ref customer
1360  $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->contrat->creer, 'string', '', 0, 1);
1361  $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->contrat->creer, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':'.$conf->global->THIRDPARTY_REF_INPUT_SIZE : ''), '', null, null, '', 1, 'getFormatedCustomerRef');
1362  // Ref supplier
1363  $morehtmlref .= '<br>';
1364  $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->contrat->creer, 'string', '', 0, 1);
1365  $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->contrat->creer, 'string', '', null, null, '', 1, 'getFormatedSupplierRef');
1366  // Thirdparty
1367  $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
1368  if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $object->thirdparty->id > 0) {
1369  $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/contrat/list.php?socid='.$object->thirdparty->id.'&search_name='.urlencode($object->thirdparty->name).'">'.$langs->trans("OtherContracts").'</a>)';
1370  }
1371  // Project
1372  if (isModEnabled('project')) {
1373  $langs->load("projects");
1374  $morehtmlref .= '<br>';
1375  if ($permissiontoadd) {
1376  $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
1377  if ($action != 'classify') {
1378  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
1379  }
1380  $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, '');
1381  } else {
1382  if (!empty($object->fk_project)) {
1383  $proj = new Project($db);
1384  $proj->fetch($object->fk_project);
1385  $morehtmlref .= $proj->getNomUrl(1);
1386  if ($proj->title) {
1387  $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
1388  }
1389  }
1390  }
1391  }
1392  $morehtmlref .= '</div>';
1393 
1394 
1395  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'none', $morehtmlref);
1396 
1397 
1398  print '<div class="fichecenter">';
1399  print '<div class="underbanner clearboth"></div>';
1400 
1401 
1402  print '<table class="border tableforfield" width="100%">';
1403 
1404  // Line info of thirdparty discounts
1405  print '<tr><td class="titlefield">'.$langs->trans('Discount').'</td><td colspan="3">';
1406  if ($object->thirdparty->remise_percent) {
1407  print $langs->trans("CompanyHasRelativeDiscount", $object->thirdparty->remise_percent).'. ';
1408  } else {
1409  print '<span class="hideonsmartphone">'.$langs->trans("CompanyHasNoRelativeDiscount").'. </span>';
1410  }
1411  $absolute_discount = $object->thirdparty->getAvailableDiscounts();
1412  if ($absolute_discount) {
1413  print $langs->trans("CompanyHasAbsoluteDiscount", price($absolute_discount), $langs->trans("Currency".$conf->currency)).'.';
1414  } else {
1415  print '<span class="hideonsmartphone">'.$langs->trans("CompanyHasNoAbsoluteDiscount").'.</span>';
1416  }
1417  print '</td></tr>';
1418 
1419  // Date
1420  print '<tr>';
1421  print '<td class="titlefield">';
1422  print $form->editfieldkey("Date", 'date_contrat', $object->date_contrat, $object, $user->rights->contrat->creer);
1423  print '</td><td>';
1424  print $form->editfieldval("Date", 'date_contrat', $object->date_contrat, $object, $user->rights->contrat->creer, 'datehourpicker');
1425  print '</td>';
1426  print '</tr>';
1427 
1428  // Other attributes
1429  $cols = 3;
1430  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
1431 
1432  print "</table>";
1433 
1434  print '</div>';
1435 
1436  if (!empty($object->brouillon) && $user->rights->contrat->creer) {
1437  print '</form>';
1438  }
1439 
1440  echo '<br>';
1441 
1442  if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) {
1443  $blocname = 'contacts';
1444  $title = $langs->trans('ContactsAddresses');
1445  include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
1446  }
1447 
1448  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
1449  $blocname = 'notes';
1450  $title = $langs->trans('Notes');
1451  include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
1452  }
1453 
1454 
1455  $arrayothercontracts = $object->getListOfContracts('others'); // array or -1 if technical error
1456 
1457  /*
1458  * Lines of contracts
1459  */
1460 
1461  // Add products/services form
1462  //$forceall = 1;
1463  global $inputalsopricewithtax;
1464  $inputalsopricewithtax = 1;
1465 
1466  $productstatic = new Product($db);
1467 
1468  $usemargins = 0;
1469  if (isModEnabled('margin') && !empty($object->element) && in_array($object->element, array('facture', 'propal', 'commande'))) {
1470  $usemargins = 1;
1471  }
1472 
1473  // Title line for service
1474  $cursorline = 1;
1475 
1476 
1477  print '<div id="contrat-lines-container" id="contractlines" data-contractid="'.$object->id.'" data-element="'.$object->element.'" >';
1478  while ($cursorline <= $nbofservices) {
1479  print '<div id="contrat-line-container'.$object->lines[$cursorline - 1]->id.'" data-contratlineid = "'.$object->lines[$cursorline - 1]->id.'" data-element="'.$object->lines[$cursorline - 1]->element.'" >';
1480  print '<form name="update" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="post">';
1481  print '<input type="hidden" name="token" value="'.newToken().'">';
1482  print '<input type="hidden" name="action" value="updateline">';
1483  print '<input type="hidden" name="elrowid" value="'.$object->lines[$cursorline - 1]->id.'">';
1484  print '<input type="hidden" name="fournprice" value="'.(!empty($object->lines[$cursorline - 1]->fk_fournprice) ? $object->lines[$cursorline - 1]->fk_fournprice : 0).'">';
1485 
1486  // Area with common detail of line
1487  print '<div class="div-table-responsive-no-min">';
1488  print '<table class="notopnoleftnoright allwidth tableforservicepart1" width="100%">';
1489 
1490  $sql = "SELECT cd.rowid, cd.statut, cd.label as label_det, cd.fk_product, cd.product_type, cd.description, cd.price_ht, cd.qty,";
1491  $sql .= " cd.tva_tx, cd.vat_src_code, cd.remise_percent, cd.info_bits, cd.subprice, cd.multicurrency_subprice,";
1492  $sql .= " cd.date_ouverture_prevue as date_start, cd.date_ouverture as date_start_real,";
1493  $sql .= " cd.date_fin_validite as date_end, cd.date_cloture as date_end_real,";
1494  $sql .= " cd.commentaire as comment, cd.fk_product_fournisseur_price as fk_fournprice, cd.buy_price_ht as pa_ht,";
1495  $sql .= " cd.fk_unit,";
1496  $sql .= " p.rowid as pid, p.ref as pref, p.label as plabel, p.fk_product_type as ptype, p.entity as pentity, p.tosell, p.tobuy, p.tobatch";
1497  $sql .= " ,cd.rang";
1498  $sql .= " FROM ".MAIN_DB_PREFIX."contratdet as cd";
1499  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON cd.fk_product = p.rowid";
1500  $sql .= " WHERE cd.rowid = ".((int) $object->lines[$cursorline - 1]->id);
1501 
1502  $result = $db->query($sql);
1503  if ($result) {
1504  $total = 0;
1505 
1506  $objp = $db->fetch_object($result);
1507 
1508  print '<tr class="liste_titre'.($cursorline ? ' liste_titre_add' : '').'">';
1509  print '<td>'.$langs->trans("ServiceNb", $cursorline).'</td>';
1510  print '<td width="80" class="center">'.$langs->trans("VAT").'</td>';
1511  print '<td width="80" class="right">'.$langs->trans("PriceUHT").'</td>';
1512  //if (isModEnabled("multicurrency")) {
1513  // print '<td width="80" class="right">'.$langs->trans("PriceUHTCurrency").'</td>';
1514  //}
1515  print '<td width="30" class="center">'.$langs->trans("Qty").'</td>';
1516  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1517  print '<td width="30" class="left">'.$langs->trans("Unit").'</td>';
1518  }
1519  print '<td width="50" class="right">'.$langs->trans("ReductionShort").'</td>';
1520  if (isModEnabled('margin') && !empty($conf->global->MARGIN_SHOW_ON_CONTRACT)) {
1521  print '<td width="50" class="right">'.$langs->trans("BuyingPrice").'</td>';
1522  }
1523  //
1524 
1525  if ($nbofservices > 1 && $conf->browser->layout != 'phone' && !empty($user->rights->contrat->creer)) {
1526  print '<td width="30" class="linecolmove tdlineupdown center">';
1527  if ($cursorline > 1) {
1528  print '<a class="lineupdown" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=up&token='.newToken().'&rowid='.$objp->rowid.'">';
1529  echo img_up('default', 0, 'imgupforline');
1530  print '</a>';
1531  }
1532  if ($cursorline < $nbofservices) {
1533  print '<a class="lineupdown" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=down&token='.newToken().'&rowid='.$objp->rowid.'">';
1534  echo img_down('default', 0, 'imgdownforline');
1535  print '</a>';
1536  }
1537  print '</td>';
1538  } else {
1539  print '<td width="30">&nbsp;</td>';
1540  }
1541 
1542  print "</tr>\n";
1543 
1544 
1545 
1546  // Line in view mode
1547  if ($action != 'editline' || GETPOST('rowid') != $objp->rowid) {
1548  $moreparam = '';
1549  if (!empty($conf->global->CONTRACT_HIDE_CLOSED_SERVICES_BY_DEFAULT) && $objp->statut == ContratLigne::STATUS_CLOSED && $action != 'showclosedlines') {
1550  $moreparam = 'style="display: none;"';
1551  }
1552  print '<tr class="tdtop oddeven" '.$moreparam.'>';
1553  // Label
1554  if ($objp->fk_product > 0) {
1555  $productstatic->id = $objp->fk_product;
1556  $productstatic->type = $objp->ptype;
1557  $productstatic->ref = $objp->pref;
1558  $productstatic->entity = $objp->pentity;
1559  $productstatic->label = $objp->plabel;
1560  $productstatic->status = $objp->tosell;
1561  $productstatic->status_buy = $objp->tobuy;
1562  $productstatic->status_batch = $objp->tobatch;
1563 
1564  print '<td>';
1565  $text = $productstatic->getNomUrl(1, '', 32);
1566  if ($objp->plabel) {
1567  $text .= ' - ';
1568  $text .= $objp->plabel;
1569  }
1570  $description = $objp->description;
1571 
1572  // Add description in form
1573  if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
1574  $text .= (!empty($objp->description) && $objp->description != $objp->plabel) ? '<br>'.dol_htmlentitiesbr($objp->description) : '';
1575  $description = ''; // Already added into main visible desc
1576  }
1577 
1578  echo $form->textwithtooltip($text, $description, 3, '', '', $cursorline, 0, (!empty($line->fk_parent_line) ?img_picto('', 'rightarrow') : ''));
1579 
1580  print '</td>';
1581  } else {
1582  print '<td>'.img_object($langs->trans("ShowProductOrService"), ($objp->product_type ? 'service' : 'product')).' '.dol_htmlentitiesbr($objp->description)."</td>\n";
1583  }
1584  // VAT
1585  print '<td class="center">';
1586  print vatrate($objp->tva_tx.($objp->vat_src_code ? (' ('.$objp->vat_src_code.')') : ''), '%', $objp->info_bits);
1587  print '</td>';
1588  // Price
1589  print '<td class="right">'.($objp->subprice != '' ? price($objp->subprice) : '')."</td>\n";
1590  // Price multicurrency
1591  /*if (isModEnabled("multicurrency")) {
1592  print '<td class="linecoluht_currency nowrap right">'.price($objp->multicurrency_subprice).'</td>';
1593  }*/
1594  // Quantity
1595  print '<td class="center">'.$objp->qty.'</td>';
1596  // Unit
1597  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1598  print '<td class="left">'.$langs->trans($object->lines[$cursorline - 1]->getLabelOfUnit()).'</td>';
1599  }
1600  // Discount
1601  if ($objp->remise_percent > 0) {
1602  print '<td class="right">'.$objp->remise_percent."%</td>\n";
1603  } else {
1604  print '<td>&nbsp;</td>';
1605  }
1606 
1607  // Margin
1608  if (isModEnabled('margin') && !empty($conf->global->MARGIN_SHOW_ON_CONTRACT)) {
1609  print '<td class="right nowraponall">'.price($objp->pa_ht).'</td>';
1610  }
1611 
1612  // Icon move, update et delete (status contract 0=draft,1=validated,2=closed)
1613  print '<td class="nowraponall right">';
1614  if ($user->rights->contrat->creer && is_array($arrayothercontracts) && count($arrayothercontracts) && ($object->statut >= 0)) {
1615  print '<!-- link to move service line into another contract -->';
1616  print '<a class="reposition marginrightonly" style="padding-left: 5px;" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=move&token='.newToken().'&rowid='.$objp->rowid.'">';
1617  print img_picto($langs->trans("MoveToAnotherContract"), 'uparrow');
1618  print '</a>';
1619  }
1620  if ($user->rights->contrat->creer && ($object->statut >= 0)) {
1621  print '<a class="reposition marginrightonly editfielda" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=editline&token='.newToken().'&rowid='.$objp->rowid.'">';
1622  print img_edit();
1623  print '</a>';
1624  }
1625  if ($user->rights->contrat->creer && ($object->statut >= 0)) {
1626  print '<a class="reposition marginrightonly" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=deleteline&token='.newToken().'&rowid='.$objp->rowid.'">';
1627  print img_delete();
1628  print '</a>';
1629  }
1630  print '</td>';
1631 
1632  print "</tr>\n";
1633 
1634  // Dates of service planed and real
1635  if ($objp->subprice >= 0) {
1636  $colspan = 6;
1637 
1638  if ($conf->margin->enabled && getDolGlobalString('PRODUCT_USE_UNITS')) {
1639  $colspan = 8;
1640  } elseif ($conf->margin->enabled || getDolGlobalString('PRODUCT_USE_UNITS')) {
1641  $colspan = 7;
1642  }
1643 
1644  print '<tr class="oddeven" '.$moreparam.'>';
1645  print '<td colspan="'.$colspan.'">';
1646 
1647  // Date planned
1648  print $langs->trans("DateStartPlanned").': ';
1649  if ($objp->date_start) {
1650  print dol_print_date($db->jdate($objp->date_start), 'day');
1651  // Warning si date prevu passee et pas en service
1652  if ($objp->statut == 0 && $db->jdate($objp->date_start) < ($now - $conf->contrat->services->inactifs->warning_delay)) {
1653  $warning_delay = $conf->contrat->services->inactifs->warning_delay / 3600 / 24;
1654  $textlate = $langs->trans("Late").' = '.$langs->trans("DateReference").' > '.$langs->trans("DateToday").' '.(ceil($warning_delay) >= 0 ? '+' : '').ceil($warning_delay).' '.$langs->trans("days");
1655  print " ".img_warning($textlate);
1656  }
1657  } else {
1658  print $langs->trans("Unknown");
1659  }
1660  print ' &nbsp;-&nbsp; ';
1661  print $langs->trans("DateEndPlanned").': ';
1662  if ($objp->date_end) {
1663  print dol_print_date($db->jdate($objp->date_end), 'day');
1664  if ($objp->statut == 4 && $db->jdate($objp->date_end) < ($now - $conf->contrat->services->expires->warning_delay)) {
1665  $warning_delay = $conf->contrat->services->expires->warning_delay / 3600 / 24;
1666  $textlate = $langs->trans("Late").' = '.$langs->trans("DateReference").' > '.$langs->trans("DateToday").' '.(ceil($warning_delay) >= 0 ? '+' : '').ceil($warning_delay).' '.$langs->trans("days");
1667  print " ".img_warning($textlate);
1668  }
1669  } else {
1670  print $langs->trans("Unknown");
1671  }
1672 
1673  print '</td>';
1674  print '</tr>';
1675  }
1676 
1677  // Display lines extrafields
1678  if (is_array($extralabelslines) && count($extralabelslines) > 0) {
1679  $line = new ContratLigne($db);
1680  $line->id = $objp->rowid;
1681  $line->fetch_optionals();
1682  print $line->showOptionals($extrafields, 'view', array('class'=>'oddeven', 'style'=>$moreparam, 'colspan'=>$colspan), '', '', 1);
1683  }
1684  } else {
1685  // Line in mode update
1686  // Ligne carac
1687  print '<tr class="oddeven">';
1688  print '<td>';
1689  if ($objp->fk_product > 0) {
1690  $canchangeproduct = 1;
1691  if (empty($canchangeproduct)) {
1692  $productstatic->id = $objp->fk_product;
1693  $productstatic->type = $objp->ptype;
1694  $productstatic->ref = $objp->pref;
1695  $productstatic->entity = $objp->pentity;
1696  print $productstatic->getNomUrl(1, '', 32);
1697  print $objp->label ? ' - '.dol_trunc($objp->label, 32) : '';
1698  print '<input type="hidden" name="idprod" value="'.(!empty($object->lines[$cursorline - 1]->fk_product) ? $object->lines[$cursorline - 1]->fk_product : 0).'">';
1699  } else {
1700  $senderissupplier = 0;
1701  if (empty($senderissupplier)) {
1702  print $form->select_produits((!empty($object->lines[$cursorline - 1]->fk_product) ? $object->lines[$cursorline - 1]->fk_product : 0), 'idprod');
1703  } else {
1704  $form->select_produits_fournisseurs((!empty($object->lines[$cursorline - 1]->fk_product) ? $object->lines[$cursorline - 1]->fk_product : 0), 'idprod');
1705  }
1706  }
1707  print '<br>';
1708  } else {
1709  print $objp->label ? $objp->label.'<br>' : '';
1710  print '<input type="hidden" name="idprod" value="'.(!empty($object->lines[$cursorline - 1]->fk_product) ? $object->lines[$cursorline - 1]->fk_product : 0).'">';
1711  }
1712 
1713  // editeur wysiwyg
1714  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1715  $nbrows = ROWS_2;
1716  if (!empty($conf->global->MAIN_INPUT_DESC_HEIGHT)) {
1717  $nbrows = $conf->global->MAIN_INPUT_DESC_HEIGHT;
1718  }
1719  $enable = (isset($conf->global->FCKEDITOR_ENABLE_DETAILS) ? $conf->global->FCKEDITOR_ENABLE_DETAILS : 0);
1720  $doleditor = new DolEditor('product_desc', $objp->description, '', 92, 'dolibarr_details', '', false, true, $enable, $nbrows, '90%');
1721  $doleditor->Create();
1722 
1723  print '</td>';
1724 
1725  // VAT
1726  print '<td class="right">';
1727  print $form->load_tva("eltva_tx", $objp->tva_tx.($objp->vat_src_code ? (' ('.$objp->vat_src_code.')') : ''), $mysoc, $object->thirdparty, $objp->fk_product, $objp->info_bits, $objp->product_type, 0, 1);
1728  print '</td>';
1729 
1730  // Price
1731  print '<td class="right"><input size="5" type="text" name="elprice" value="'.price($objp->subprice).'"></td>';
1732 
1733  // Price multicurrency
1734  /*if (isModEnabled("multicurrency")) {
1735  print '<td class="linecoluht_currency nowrap right">'.price($objp->multicurrency_subprice).'</td>';
1736  }*/
1737 
1738  // Quantity
1739  print '<td class="center"><input size="2" type="text" name="elqty" value="'.$objp->qty.'"></td>';
1740 
1741  // Unit
1742  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1743  print '<td class="left">';
1744  print $form->selectUnits($objp->fk_unit, "unit");
1745  print '</td>';
1746  }
1747 
1748  // Discount
1749  print '<td class="nowrap right"><input size="1" type="text" name="elremise_percent" value="'.$objp->remise_percent.'">%</td>';
1750 
1751  if (!empty($usemargins)) {
1752  print '<td class="right">';
1753  if ($objp->fk_product) {
1754  print '<select id="fournprice" name="fournprice"></select>';
1755  }
1756  print '<input id="buying_price" type="text" size="5" name="buying_price" value="'.price($objp->pa_ht, 0, '', 0).'"></td>';
1757  }
1758  print '<td class="center">';
1759  print '<input type="submit" class="button margintoponly marginbottomonly" name="save" value="'.$langs->trans("Modify").'">';
1760  print '<br><input type="submit" class="button margintoponly marginbottomonly button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
1761  print '</td>';
1762  print '</tr>';
1763 
1764  $colspan = 6;
1765  if (isModEnabled('margin') && !empty($conf->global->MARGIN_SHOW_ON_CONTRACT)) {
1766  $colspan++;
1767  }
1768  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1769  $colspan++;
1770  }
1771 
1772  // Line dates planed
1773  print '<tr class="oddeven">';
1774  print '<td colspan="'.$colspan.'">';
1775  print $langs->trans("DateStartPlanned").' ';
1776  print $form->selectDate($db->jdate($objp->date_start), "date_start_update", $usehm, $usehm, ($db->jdate($objp->date_start) > 0 ? 0 : 1), "update");
1777  print ' &nbsp;&nbsp;'.$langs->trans("DateEndPlanned").' ';
1778  print $form->selectDate($db->jdate($objp->date_end), "date_end_update", $usehm, $usehm, ($db->jdate($objp->date_end) > 0 ? 0 : 1), "update");
1779  print '</td>';
1780  print '</tr>';
1781 
1782  if (is_array($extralabelslines) && count($extralabelslines) > 0) {
1783  $line = new ContratLigne($db);
1784  $line->id = $objp->rowid;
1785  $line->fetch_optionals();
1786  print $line->showOptionals($extrafields, 'edit', array('style'=>'class="oddeven"', 'colspan'=>$colspan), '', '', 1);
1787  }
1788  }
1789 
1790  $db->free($result);
1791  } else {
1792  dol_print_error($db);
1793  }
1794 
1795  if ($object->statut > 0) {
1796  $moreparam = '';
1797  if (!empty($conf->global->CONTRACT_HIDE_CLOSED_SERVICES_BY_DEFAULT) && $object->lines[$cursorline - 1]->statut == ContratLigne::STATUS_CLOSED && $action != 'showclosedlines') {
1798  $moreparam = 'style="display: none;"';
1799  }
1800  print '<tr class="oddeven" '.$moreparam.'>';
1801  print '<td class="tdhrthin" colspan="'.($conf->margin->enabled ? 7 : 6).'"><hr class="opacitymedium tdhrthin"></td>';
1802  print "</tr>\n";
1803  }
1804 
1805  print "</table>";
1806  print '</div>';
1807 
1808  print "</form>\n";
1809 
1810 
1811  /*
1812  * Confirmation to delete service line of contract
1813  */
1814  if ($action == 'deleteline' && !$_REQUEST["cancel"] && $user->rights->contrat->creer && $object->lines[$cursorline - 1]->id == GETPOST('rowid')) {
1815  print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&lineid=".GETPOST('rowid'), $langs->trans("DeleteContractLine"), $langs->trans("ConfirmDeleteContractLine"), "confirm_deleteline", '', 0, 1);
1816  if ($ret == 'html') {
1817  print '<table class="notopnoleftnoright" width="100%"><tr class="oddeven" height="6"><td></td></tr></table>';
1818  }
1819  }
1820 
1821  /*
1822  * Confirmation to move service toward another contract
1823  */
1824  if ($action == 'move' && !$_REQUEST["cancel"] && $user->rights->contrat->creer && $object->lines[$cursorline - 1]->id == GETPOST('rowid')) {
1825  $arraycontractid = array();
1826  foreach ($arrayothercontracts as $contractcursor) {
1827  $arraycontractid[$contractcursor->id] = $contractcursor->ref;
1828  }
1829  //var_dump($arraycontractid);
1830  // Cree un tableau formulaire
1831  $formquestion = array(
1832  'text' => $langs->trans("ConfirmMoveToAnotherContractQuestion"),
1833  array('type' => 'select', 'name' => 'newcid', 'values' => $arraycontractid));
1834 
1835  print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&lineid=".GETPOST('rowid', 'int'), $langs->trans("MoveToAnotherContract"), $langs->trans("ConfirmMoveToAnotherContract"), "confirm_move", $formquestion);
1836  print '<table class="notopnoleftnoright" width="100%"><tr class="oddeven" height="6"><td></td></tr></table>';
1837  }
1838 
1839  /*
1840  * Confirmation de la validation activation
1841  */
1842  if ($action == 'active' && !$cancel && $user->rights->contrat->activer && $object->lines[$cursorline - 1]->id == GETPOST('ligne', 'int')) {
1843  $dateactstart = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
1844  $dateactend = dol_mktime(12, 0, 0, GETPOST('endmonth'), GETPOST('endday'), GETPOST('endyear'));
1845  $comment = GETPOST('comment', 'alpha');
1846  print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne', 'int')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment), $langs->trans("ActivateService"), $langs->trans("ConfirmActivateService", dol_print_date($dateactstart, "%A %d %B %Y")), "confirm_active", '', 0, 1);
1847  print '<table class="notopnoleftnoright" width="100%"><tr class="oddeven" height="6"><td></td></tr></table>';
1848  }
1849 
1850  /*
1851  * Confirmation de la validation fermeture
1852  */
1853  if ($action == 'closeline' && !$cancel && $user->rights->contrat->activer && $object->lines[$cursorline - 1]->id == GETPOST('ligne', 'int')) {
1854  $dateactstart = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
1855  $dateactend = dol_mktime(12, 0, 0, GETPOST('endmonth'), GETPOST('endday'), GETPOST('endyear'));
1856  $comment = GETPOST('comment', 'alpha');
1857 
1858  if (empty($dateactend)) {
1859  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("DateEndReal")), null, 'errors');
1860  } else {
1861  print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne', 'int')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment), $langs->trans("CloseService"), $langs->trans("ConfirmCloseService", dol_print_date($dateactend, "%A %d %B %Y")), "confirm_closeline", '', 0, 1);
1862  }
1863  print '<table class="notopnoleftnoright" width="100%"><tr class="oddeven" height="6"><td></td></tr></table>';
1864  }
1865 
1866 
1867  // Area with status and activation info of line
1868  if ($object->statut > 0) {
1869  print '<table class="notopnoleftnoright tableforservicepart2'.($cursorline < $nbofservices ? ' boxtablenobottom' : '').'" width="100%">';
1870 
1871  print '<tr class="oddeven" '.$moreparam.'>';
1872  print '<td><span class="valignmiddle hideonsmartphone">'.$langs->trans("ServiceStatus").':</span> '.$object->lines[$cursorline - 1]->getLibStatut(4).'</td>';
1873  print '<td width="30" class="right">';
1874  if ($user->socid == 0) {
1875  if ($object->statut > 0 && $action != 'activateline' && $action != 'unactivateline') {
1876  $tmpaction = 'activateline';
1877  $tmpactionpicto = 'play';
1878  $tmpactiontext = $langs->trans("Activate");
1879  if ($objp->statut == 4) {
1880  $tmpaction = 'unactivateline';
1881  $tmpactionpicto = 'playstop';
1882  $tmpactiontext = $langs->trans("Disable");
1883  }
1884  if (($tmpaction == 'activateline' && $user->rights->contrat->activer) || ($tmpaction == 'unactivateline' && $user->rights->contrat->desactiver)) {
1885  print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;ligne='.$object->lines[$cursorline - 1]->id.'&amp;action='.$tmpaction.'">';
1886  print img_picto($tmpactiontext, $tmpactionpicto);
1887  print '</a>';
1888  }
1889  }
1890  }
1891  print '</td>';
1892  print "</tr>\n";
1893 
1894  print '<tr class="oddeven" '.$moreparam.'>';
1895 
1896  print '<td>';
1897  // Si pas encore active
1898  if (!$objp->date_start_real) {
1899  print $langs->trans("DateStartReal").': ';
1900  if ($objp->date_start_real) {
1901  print dol_print_date($db->jdate($objp->date_start_real), 'day');
1902  } else {
1903  print $langs->trans("ContractStatusNotRunning");
1904  }
1905  }
1906  // Si active et en cours
1907  if ($objp->date_start_real && !$objp->date_end_real) {
1908  print $langs->trans("DateStartReal").': ';
1909  print dol_print_date($db->jdate($objp->date_start_real), 'day');
1910  }
1911  // Si desactive
1912  if ($objp->date_start_real && $objp->date_end_real) {
1913  print $langs->trans("DateStartReal").': ';
1914  print dol_print_date($db->jdate($objp->date_start_real), 'day');
1915  print ' &nbsp;-&nbsp; ';
1916  print $langs->trans("DateEndReal").': ';
1917  print dol_print_date($db->jdate($objp->date_end_real), 'day');
1918  }
1919  if (!empty($objp->comment)) {
1920  print " &nbsp;-&nbsp; ".$objp->comment;
1921  }
1922  print '</td>';
1923 
1924  print '<td class="center">&nbsp;</td>';
1925 
1926  print '</tr>';
1927  print '</table>';
1928  }
1929 
1930  // Form to activate line
1931  if ($user->rights->contrat->activer && $action == 'activateline' && $object->lines[$cursorline - 1]->id == GETPOST('ligne', 'int')) {
1932  print '<form name="active" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;ligne='.GETPOST('ligne', 'int').'&amp;action=active" method="post">';
1933  print '<input type="hidden" name="token" value="'.newToken().'">';
1934 
1935  print '<table class="noborder tableforservicepart2'.($cursorline < $nbofservices ? ' boxtablenobottom' : '').'" width="100%">';
1936 
1937  // Definie date debut et fin par defaut
1938  $dateactstart = $objp->date_start;
1939  if (GETPOST('remonth')) {
1940  $dateactstart = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
1941  } elseif (!$dateactstart) {
1942  $dateactstart = time();
1943  }
1944 
1945  $dateactend = $objp->date_end;
1946  if (GETPOST('endmonth')) {
1947  $dateactend = dol_mktime(12, 0, 0, GETPOST('endmonth'), GETPOST('endday'), GETPOST('endyear'));
1948  } elseif (!$dateactend) {
1949  if ($objp->fk_product > 0) {
1950  $product = new Product($db);
1951  $product->fetch($objp->fk_product);
1952  $dateactend = dol_time_plus_duree(time(), $product->duration_value, $product->duration_unit);
1953  }
1954  }
1955 
1956  print '<tr class="oddeven">';
1957  print '<td class="nohover">'.$langs->trans("DateServiceActivate").'</td><td class="nohover">';
1958  print $form->selectDate($dateactstart, '', $usehm, $usehm, '', "active", 1, 0);
1959  print '</td>';
1960  print '<td class="nohover">'.$langs->trans("DateEndPlanned").'</td><td class="nohover">';
1961  print $form->selectDate($dateactend, "end", $usehm, $usehm, '', "active", 1, 0);
1962  print '</td>';
1963  print '<td class="center nohover">';
1964  print '</td>';
1965 
1966  print '</tr>';
1967 
1968  print '<tr class="oddeven">';
1969  print '<td class="nohover">'.$langs->trans("Comment").'</td><td colspan="3" class="nohover" colspan="'.($conf->margin->enabled ? 4 : 3).'"><input type="text" class="minwidth300" name="comment" value="'.dol_escape_htmltag(GETPOST("comment", 'alphanohtml')).'"></td>';
1970  print '<td class="nohover right">';
1971  print '<input type="submit" class="button" name="activate" value="'.$langs->trans("Activate").'"> &nbsp; ';
1972  print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
1973  print '</td>';
1974  print '</tr>';
1975 
1976  print '</table>';
1977 
1978  print '</form>';
1979  }
1980 
1981  if ($user->rights->contrat->activer && $action == 'unactivateline' && $object->lines[$cursorline - 1]->id == GETPOST('ligne', 'int')) {
1985  print '<!-- Form to disabled a line -->'."\n";
1986  print '<form name="closeline" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;ligne='.$object->lines[$cursorline - 1]->id.'" method="post">';
1987 
1988  print '<input type="hidden" name="token" value="'.newToken().'">';
1989  print '<input type="hidden" name="action" value="closeline">';
1990 
1991  print '<table class="noborder tableforservicepart2'.($cursorline < $nbofservices ? ' boxtablenobottom' : '').'" width="100%">';
1992 
1993  // Definie date debut et fin par defaut
1994  $dateactstart = $objp->date_start_real;
1995  if (GETPOST('remonth')) {
1996  $dateactstart = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
1997  } elseif (!$dateactstart) {
1998  $dateactstart = time();
1999  }
2000 
2001  $dateactend = $objp->date_end_real;
2002  if (GETPOST('endmonth')) {
2003  $dateactend = dol_mktime(12, 0, 0, GETPOST('endmonth'), GETPOST('endday'), GETPOST('endyear'));
2004  } elseif (!$dateactend) {
2005  if ($objp->fk_product > 0) {
2006  $product = new Product($db);
2007  $product->fetch($objp->fk_product);
2008  $dateactend = dol_time_plus_duree(time(), $product->duration_value, $product->duration_unit);
2009  }
2010  }
2011  $now = dol_now();
2012  if ($dateactend > $now) {
2013  $dateactend = $now;
2014  }
2015 
2016  print '<tr class="oddeven"><td colspan="2" class="nohover">';
2017  if ($objp->statut >= 4) {
2018  if ($objp->statut == 4) {
2019  print $langs->trans("DateEndReal").' ';
2020  print $form->selectDate($dateactend, "end", $usehm, $usehm, ($objp->date_end_real > 0 ? 0 : 1), "closeline", 1, 1);
2021  }
2022  }
2023  print '</td>';
2024  print '<td class="center nohover">';
2025  print '</td></tr>';
2026 
2027  print '<tr class="oddeven">';
2028  print '<td class="nohover">'.$langs->trans("Comment").'</td><td class="nohover"><input class="quatrevingtpercent" type="text" class="flat" name="comment" value="'.dol_escape_htmltag(GETPOST('comment', 'alpha')).'"></td>';
2029  print '<td class="nohover right">';
2030  print '<input type="submit" class="button" name="close" value="'.$langs->trans("Disable").'"> &nbsp; ';
2031  print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
2032  print '</td>';
2033  print '</tr>';
2034 
2035  print '</table>';
2036 
2037  print '</form>';
2038  }
2039  print '</div>';
2040  $cursorline++;
2041  }
2042  print '</div>';
2043 
2044  // Form to add new line
2045  if ($user->rights->contrat->creer && ($object->statut == 0)) {
2046  $dateSelector = 1;
2047 
2048  print "\n";
2049  print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.(($action != 'editline') ? '#add' : '#line_'.GETPOST('lineid', 'int')).'" method="POST">
2050  <input type="hidden" name="token" value="'.newToken().'">
2051  <input type="hidden" name="action" value="'.(($action != 'editline') ? 'addline' : 'updateline').'">
2052  <input type="hidden" name="mode" value="">
2053  <input type="hidden" name="id" value="'.$object->id.'">
2054  ';
2055 
2056  print '<div class="div-table-responsive-no-min">';
2057  print '<table id="tablelines" class="noborder noshadow" width="100%">'; // Array with (n*2)+1 lines
2058 
2059  // Form to add new line
2060  if ($action != 'editline') {
2061  $forcetoshowtitlelines = 1;
2062  if (empty($object->multicurrency_code)) {
2063  $object->multicurrency_code = $conf->currency; // TODO Remove this when multicurrency supported on contracts
2064  }
2065 
2066  // Add free products/services
2067 
2068  $parameters = array();
2069  $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2070  if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2071  if (empty($reshook))
2072  $object->formAddObjectLine(1, $mysoc, $soc);
2073  }
2074 
2075  print '</table>';
2076  print '</div>';
2077  print '</form>';
2078  }
2079 
2080  print dol_get_fiche_end();
2081 
2082  // Select mail models is same action as presend
2083  if (GETPOST('modelselected')) {
2084  $action = 'presend';
2085  }
2086 
2087  /*
2088  * Buttons
2089  */
2090  if ($user->socid == 0 && $action != 'presend' && $action != 'editline') {
2091  print '<div class="tabsAction">';
2092 
2093  $parameters = array();
2094  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2095 
2096  if (empty($reshook)) {
2097  $params = array(
2098  'attr' => array(
2099  'title' => '',
2100  'class' => 'classfortooltip'
2101  )
2102  );
2103 
2104  // Send
2105  if (empty($user->socid)) {
2106  if ($object->statut == 1) {
2107  if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->contrat->creer)) {
2108  print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=presend&token='.newToken().'&mode=init#formmailbeforetitle', '', true, $params);
2109  } else {
2110  print dolGetButtonAction('', $langs->trans('SendMail'), 'default', '#', '', false, $params);
2111  }
2112  }
2113  }
2114 
2115  if ($object->statut == 0 && $nbofservices) {
2116  if ($user->rights->contrat->creer) {
2117  print dolGetButtonAction($langs->trans('Validate'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=valid&token='.newToken(), '', true, $params);
2118  } else {
2119  $params['attr']['title'] = $langs->trans("NotEnoughPermissions");
2120  print dolGetButtonAction($langs->trans('Validate'), '', 'default', '#', '', false, $params);
2121  }
2122  }
2123  if ($object->statut == 1) {
2124  if ($user->rights->contrat->creer) {
2125  print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken(), '', true, $params);
2126  } else {
2127  $params['attr']['title'] = $langs->trans("NotEnoughPermissions");
2128  print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
2129  }
2130  }
2131 
2132  if (isModEnabled('commande') && $object->statut > 0 && $object->nbofservicesclosed < $nbofservices) {
2133  $langs->load("orders");
2134  if ($user->rights->commande->creer) {
2135  print dolGetButtonAction($langs->trans('CreateOrder'), '', 'default', DOL_URL_ROOT.'/commande/card.php?action=create&token='.newToken().'&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->thirdparty->id, '', true, $params);
2136  } else {
2137  $params['attr']['title'] = $langs->trans("NotEnoughPermissions");
2138  print dolGetButtonAction($langs->trans('CreateOrder'), '', 'default', '#', '', false, $params);
2139  }
2140  }
2141 
2142  if (isModEnabled('facture') && $object->statut > 0) {
2143  $langs->load("bills");
2144  if ($user->rights->facture->creer) {
2145  print dolGetButtonAction($langs->trans('CreateBill'), '', 'default', DOL_URL_ROOT.'/compta/facture/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->thirdparty->id, '', true, $params);
2146  } else {
2147  $params['attr']['title'] = $langs->trans("NotEnoughPermissions");
2148  print dolGetButtonAction($langs->trans('CreateBill'), '', 'default', '#', '', false, $params);
2149  }
2150  }
2151 
2152  if ($object->nbofservicesclosed > 0 || $object->nbofserviceswait > 0) {
2153  if ($user->rights->contrat->activer) {
2154  print dolGetButtonAction($langs->trans('ActivateAllContracts'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=activate&token='.newToken(), '', true, $params);
2155  } else {
2156  print dolGetButtonAction($langs->trans('ActivateAllContracts'), '', 'default', '#', '', false, $params);
2157  }
2158  }
2159  if ($object->nbofservicesclosed < $nbofservices) {
2160  if ($user->rights->contrat->desactiver) {
2161  print dolGetButtonAction($langs->trans('CloseAllContracts'), '', 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=close&token='.newToken(), '', true, $params);
2162  } else {
2163  print dolGetButtonAction($langs->trans('CloseAllContracts'), '', 'default', '#', '', false, $params);
2164  }
2165 
2166  //if (! $numactive)
2167  //{
2168  //}
2169  //else
2170  //{
2171  // print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("CloseRefusedBecauseOneServiceActive").'">'.$langs->trans("Close").'</a></div>';
2172  //}
2173  }
2174 
2175  if (!empty($conf->global->CONTRACT_HIDE_CLOSED_SERVICES_BY_DEFAULT) && $object->nbofservicesclosed > 0) {
2176  if ($action == 'showclosedlines') {
2177  print '<div class="inline-block divButAction"><a class="butAction" id="btnhideclosedlines" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=hideclosedlines">'.$langs->trans("HideClosedServices").'</a></div>';
2178  } else {
2179  print '<div class="inline-block divButAction"><a class="butAction" id="btnshowclosedlines" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=showclosedlines">'.$langs->trans("ShowClosedServices").'</a></div>';
2180  }
2181  }
2182 
2183  // Clone
2184  if ($user->rights->contrat->creer) {
2185  print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&socid='.$object->socid.'&action=clone&token='.newToken(), '', true, $params);
2186  }
2187 
2188  // Delete
2189  print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), '', $permissiontodelete, $params);
2190  }
2191 
2192  print "</div>";
2193  }
2194 
2195  if ($action != 'presend') {
2196  print '<div class="fichecenter"><div class="fichehalfleft">';
2197 
2198  /*
2199  * Generated documents
2200  */
2201  $filename = dol_sanitizeFileName($object->ref);
2202  $filedir = $conf->contrat->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
2203  $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
2204  $genallowed = $user->rights->contrat->lire;
2205  $delallowed = $user->rights->contrat->creer;
2206 
2207 
2208  print $formfile->showdocuments('contract', $filename, $filedir, $urlsource, $genallowed, $delallowed, ($object->model_pdf ? $object->model_pdf : getDolGlobalString('CONTRACT_ADDON_PDF')), 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang, '', $object);
2209 
2210 
2211  // Show links to link elements
2212  $linktoelem = $form->showLinkToObjectBlock($object, null, array('contrat'));
2213  $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
2214 
2215  // Show online signature link
2216  if ($object->statut != Contrat::STATUS_DRAFT && getDolGlobalString('CONTRACT_ALLOW_ONLINESIGN')) {
2217  print '<br><!-- Link to sign -->';
2218  require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
2219 
2220  print showOnlineSignatureUrl('contract', $object->ref).'<br>';
2221  }
2222 
2223  print '</div><div class="fichehalfright">';
2224 
2225  $MAXEVENT = 10;
2226 
2227  $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/contrat/agenda.php?id='.$object->id);
2228 
2229 
2230  // List of actions on element
2231  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
2232  $formactions = new FormActions($db);
2233  $somethingshown = $formactions->showactions($object, 'contract', $socid, 1, 'listactions', $MAXEVENT, '', $morehtmlcenter);
2234 
2235  print '</div></div>';
2236  }
2237 
2238  // Presend form
2239  $modelmail = 'contract';
2240  $defaulttopic = 'SendContractRef';
2241  $diroutput = $conf->contrat->multidir_output[$object->entity];
2242  $trackid = 'con'.$object->id;
2243 
2244  include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
2245  }
2246 }
2247 
2248 
2249 llxFooter();
2250 
2251 $db->close();
2252 ?>
2253 
2254 <?php
2255 if (isModEnabled('margin') && $action == 'editline') {
2256  // TODO Why this ? To manage margin on contracts ?
2257  ?>
2258 <script type="text/javascript">
2259 $(document).ready(function() {
2260  var idprod = $("input[name='idprod']").val();
2261  var fournprice = $("input[name='fournprice']").val();
2262  var token = '<?php echo currentToken(); ?>'; // For AJAX Call we use old 'token' and not 'newtoken'
2263  if (idprod > 0) {
2264  $.post('<?php echo DOL_URL_ROOT; ?>/fourn/ajax/getSupplierPrices.php', {
2265  'idprod': idprod,
2266  'token': token
2267  }, function(data) {
2268  if (data.length > 0) {
2269  var options = '';
2270  var trouve=false;
2271  $(data).each(function() {
2272  options += '<option value="'+this.id+'" price="'+this.price+'"';
2273  if (fournprice > 0) {
2274  if (this.id == fournprice) {
2275  options += ' selected';
2276  $("#buying_price").val(this.price);
2277  trouve = true;
2278  }
2279  }
2280  options += '>'+this.label+'</option>';
2281  });
2282  options += '<option value=null'+(trouve?'':' selected')+'><?php echo $langs->trans("InputPrice"); ?></option>';
2283  $("#fournprice").html(options);
2284  if (trouve) {
2285  $("#buying_price").hide();
2286  $("#fournprice").show();
2287  }
2288  else {
2289  $("#buying_price").show();
2290  }
2291  $("#fournprice").change(function() {
2292  var selval = $(this).find('option:selected').attr("price");
2293  if (selval)
2294  $("#buying_price").val(selval).hide();
2295  else
2296  $('#buying_price').show();
2297  });
2298  }
2299  else {
2300  $("#fournprice").hide();
2301  $('#buying_price').show();
2302  }
2303  },
2304  'json');
2305  }
2306  else {
2307  $("#fournprice").hide();
2308  $('#buying_price').show();
2309  }
2310 });
2311 </script>
2312  <?php
2313 }
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 contracts.
Class to manage lines of contracts.
Class to manage a WYSIWYG editor.
Class to manage standard extra fields.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class to manage building of HTML components.
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 third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:45
$parameters
Actions.
Definition: card.php:79
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
contract_prepare_head(Contrat $object)
Prepare array with list of tabs.
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:121
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:61
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:874
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...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
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_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
img_down($titlealt='default', $selected=0, $moreclass='')
Show down arrow logo.
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)
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.
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.
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.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
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...
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
$formconfirm
if ($action == 'delbookkeepingyear') {
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
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.