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