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