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