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