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