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