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