dolibarr 24.0.0-beta
contratligne.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Destailleur Laurent <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) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr>
7 * Copyright (C) 2010-2016 Juanjo Menent <jmenent@2byte.es>
8 * Copyright (C) 2013 Christophe Battarel <christophe.battarel@altairis.fr>
9 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
10 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
11 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
12 * Copyright (C) 2018-2025 Frédéric France <frederic.france@free.fr>
13 * Copyright (C) 2015-2018 Ferran Marcet <fmarcet@2byte.es>
14 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
15 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29 */
30
37require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php";
38require_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
39require_once DOL_DOCUMENT_ROOT.'/margin/lib/margins.lib.php';
40
45{
49 public $element = 'contratdet';
50
54 public $table_element = 'contratdet';
55
59 public $parent_element = 'contrat';
60
64 public $fk_parent_attribute = 'fk_contrat';
65
70 public $element_for_permission = 'contrat';
71
75 public $id;
76
80 public $ref;
81
85 public $fk_contrat;
86
90 public $fk_product;
91
95 public $statut;
96
100 public $type;
101
106 public $label;
107
112 public $libelle;
113
117 public $description;
118
122 public $product_type;
123
127 public $product_ref;
128
132 public $product_label;
133
137 public $date_commande;
138
142 public $date_start;
143
147 public $date_start_real;
148
152 public $date_end;
153
157 public $date_end_real;
158
162 public $tva_tx;
163
167 public $vat_src_code;
168
172 public $localtax1_tx;
173
177 public $localtax2_tx;
178
182 public $localtax1_type;
183
187 public $localtax2_type;
188
192 public $qty;
193
197 public $remise_percent;
198
202 public $fk_remise_except;
203
207 public $subprice;
208
212 public $total_ht;
213
217 public $total_tva;
218
222 public $total_localtax1;
223
227 public $total_localtax2;
228
232 public $total_ttc;
233
237 public $fk_fournprice;
238
242 public $pa_ht;
243
247 public $info_bits;
248
252 public $fk_user_author;
253
257 public $fk_user_ouverture;
258
262 public $fk_user_cloture;
263
267 public $commentaire;
268
269
273 public $rang = 0;
274
275
276 const STATUS_INITIAL = 0;
277 const STATUS_OPEN = 4;
278 const STATUS_CLOSED = 5;
279
280
281 // BEGIN MODULEBUILDER PROPERTIES
285 public $fields = array(
286 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
287 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 30, 'index' => 1),
288 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35),
289 'qty' => array('type' => 'integer', 'label' => 'Quantity', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'position' => 35, 'isameasure' => 1),
290 'total_ht' => array('type' => 'integer', 'label' => 'AmountHT', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 36, 'isameasure' => 1),
291 'total_tva' => array('type' => 'integer', 'label' => 'AmountVAT', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 37, 'isameasure' => 1),
292 'total_ttc' => array('type' => 'integer', 'label' => 'AmountTTC', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 38, 'isameasure' => 1),
293 //'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
294 //'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>70),
295 'fk_contrat' => array('type' => 'integer:Contrat:contrat/class/contrat.class.php', 'label' => 'Contract', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 70),
296 'fk_product' => array('type' => 'integer:Product:product/class/product.class.php:1', 'label' => 'Product', 'enabled' => 1, 'visible' => -1, 'position' => 75),
297 //'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>90),
298 'note_private' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 105),
299 'note_public' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 110),
300 //'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>115),
301 //'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>120),
302 //'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
303 'fk_user_ouverture' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserStartingService', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 135),
304 'fk_user_cloture' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserClosingService', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 135),
305 'statut' => array('type' => 'smallint(6)', 'label' => 'Statut', 'enabled' => 1, 'visible' => -1, 'position' => 500, 'arrayofkeyval' => array(0 => 'Draft', 4 => 'Open', 5 => 'Closed')),
306 'rang' => array('type' => 'integer', 'label' => 'Rank', 'enabled' => 1, 'visible' => 0, 'position' => 500, 'default' => '0')
307 );
308 // END MODULEBUILDER PROPERTIES
309
310
316 public function __construct($db)
317 {
318 $this->db = $db;
319 }
320
321
328 public function getLibStatut($mode)
329 {
330 return $this->LibStatut($this->statut, $mode, ((!empty($this->date_end)) ? ($this->date_end < dol_now() ? 1 : 0) : -1));
331 }
332
333 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
344 public static function LibStatut($status, $mode, $expired = -1, $moreatt = '', $morelabel = '')
345 {
346 // phpcs:enable
347 global $langs;
348 $langs->load("contracts");
349
350 if ($status == self::STATUS_INITIAL) {
351 $labelStatus = $langs->transnoentities("ServiceStatusInitial");
352 $labelStatusShort = $langs->transnoentities("ServiceStatusInitial");
353 } elseif ($status == self::STATUS_OPEN && $expired == -1) {
354 $labelStatus = $langs->transnoentities("ServiceStatusRunning");
355 $labelStatusShort = $langs->transnoentities("ServiceStatusRunning");
356 } elseif ($status == self::STATUS_OPEN && $expired == 0) {
357 $labelStatus = $langs->transnoentities("ServiceStatusNotLate");
358 $labelStatusShort = $langs->transnoentities("ServiceStatusNotLateShort");
359 } elseif ($status == self::STATUS_OPEN && $expired == 1) {
360 $labelStatus = $langs->transnoentities("ServiceStatusLate");
361 $labelStatusShort = $langs->transnoentities("ServiceStatusLateShort");
362 } elseif ($status == self::STATUS_CLOSED) {
363 $labelStatus = $langs->transnoentities("ServiceStatusClosed");
364 $labelStatusShort = $langs->transnoentities("ServiceStatusClosed");
365 } else {
366 $labelStatus = '';
367 $labelStatusShort = '';
368 }
369
370 $statusType = 'status'.$status;
371 if ($status == self::STATUS_OPEN && $expired == 1) {
372 $statusType = 'status1';
373 }
374 if ($status == self::STATUS_CLOSED) {
375 $statusType = 'status6';
376 }
377
378 $params = array();
379 $reg = array();
380 if (preg_match('/class="(.*)"/', $moreatt, $reg)) {
381 $params = array('badgeParams' => array('css' => $reg[1]));
382 }
383 return dolGetStatus($labelStatus.($morelabel ? ' '.$morelabel : ''), $labelStatusShort.($morelabel ? ' '.$morelabel : ''), '', $statusType, $mode, '', $params);
384 }
385
392 public function getTooltipContentArray($params)
393 {
394 global $conf, $langs, $user;
395
396 $datas = [];
397 $datas['label'] = $langs->trans("ShowContractOfService").': '.$this->label;
398 if (empty($this->label)) {
399 $datas['label'] = $this->description;
400 }
401
402 return $datas;
403 }
404
412 public function getNomUrl($withpicto = 0, $maxlength = 0)
413 {
414 global $langs;
415
416 $result = '';
417 $label = $langs->trans("ShowContractOfService").': '.$this->label;
418 if (empty($this->label)) {
419 $label = $this->description;
420 }
421 $classfortooltip = 'classfortooltip';
422 $dataparams = '';
423 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
424 $params = [
425 'id' => $this->fk_contrat,
426 'objecttype' => $this->element,
427 ];
428 $classfortooltip = 'classforajaxtooltip';
429 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
430 $label = '';
431 }
432
433 $link = '<a href="'.DOL_URL_ROOT.'/contrat/card.php?id='.$this->fk_contrat.'"';
434 $link .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
435 $link .= $dataparams.' class="'.$classfortooltip.'">';
436 $linkend = '</a>';
437
438 $picto = 'service';
439 if ($this->type == 0) {
440 $picto = 'product';
441 }
442
443 if ($withpicto) {
444 $result .= ($link.img_object($label, $picto, $dataparams.' class="'.$classfortooltip.'"').$linkend);
445 }
446 if ($withpicto && $withpicto != 2) {
447 $result .= ' ';
448 }
449 if ($withpicto != 2) {
450 $result .= $link.($this->product_ref ? $this->product_ref.' ' : '').($this->label ? $this->label : $this->description).$linkend;
451 }
452 return $result;
453 }
454
462 public function fetch($id, $ref = '')
463 {
464 // Check parameters
465 if (empty($id) && empty($ref)) {
466 return -1;
467 }
468
469 $sql = "SELECT";
470 $sql .= " t.rowid,";
471 $sql .= " t.tms,";
472 $sql .= " t.fk_contrat,";
473 $sql .= " t.fk_product,";
474 $sql .= " t.statut,";
475 $sql .= " t.label,"; // This field is not used. Only label of product
476 $sql .= " p.ref as product_ref,";
477 $sql .= " p.label as product_label,";
478 $sql .= " p.description as product_description,";
479 $sql .= " p.fk_product_type as product_type,";
480 $sql .= " t.description,";
481 $sql .= " t.date_commande,";
482 $sql .= " t.date_ouverture_prevue as date_start,";
483 $sql .= " t.date_ouverture as date_start_real,";
484 $sql .= " t.date_fin_validite as date_end,";
485 $sql .= " t.date_cloture as date_end_real,";
486 $sql .= " t.tva_tx,";
487 $sql .= " t.vat_src_code,";
488 $sql .= " t.localtax1_tx,";
489 $sql .= " t.localtax2_tx,";
490 $sql .= " t.localtax1_type,";
491 $sql .= " t.localtax2_type,";
492 $sql .= " t.qty,";
493 $sql .= " t.remise_percent,";
494 $sql .= " t.fk_remise_except,";
495 $sql .= " t.subprice,";
496 $sql .= " t.total_ht,";
497 $sql .= " t.total_tva,";
498 $sql .= " t.total_localtax1,";
499 $sql .= " t.total_localtax2,";
500 $sql .= " t.total_ttc,";
501 $sql .= " t.fk_product_fournisseur_price as fk_fournprice,";
502 $sql .= " t.buy_price_ht as pa_ht,";
503 $sql .= " t.info_bits,";
504 $sql .= " t.fk_user_author,";
505 $sql .= " t.fk_user_ouverture,";
506 $sql .= " t.fk_user_cloture,";
507 $sql .= " t.commentaire,";
508 $sql .= " t.fk_unit,";
509 $sql .= " t.extraparams,";
510 $sql .= " t.rang";
511 $sql .= " FROM ".MAIN_DB_PREFIX."contratdet as t LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = t.fk_product";
512 if ($id) {
513 $sql .= " WHERE t.rowid = ".((int) $id);
514 }
515 if ($ref) {
516 $sql .= " WHERE t.rowid = '".$this->db->escape($ref)."'";
517 }
518
519 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
520 $resql = $this->db->query($sql);
521 if ($resql) {
522 if ($this->db->num_rows($resql)) {
523 $obj = $this->db->fetch_object($resql);
524
525 $this->id = $obj->rowid;
526 $this->ref = $obj->rowid;
527
528 $this->tms = $this->db->jdate($obj->tms);
529 $this->fk_contrat = $obj->fk_contrat;
530 $this->fk_product = $obj->fk_product;
531 $this->statut = $obj->statut;
532 $this->product_ref = $obj->product_ref;
533 $this->product_label = $obj->product_label;
534 $this->product_type = $obj->product_type;
535 $this->label = $obj->label; // deprecated. We do not use this field. Only ref and label of product, and description of contract line
536 $this->description = $obj->description;
537 $this->date_commande = $this->db->jdate($obj->date_commande);
538
539 $this->date_start = $this->db->jdate($obj->date_start);
540 $this->date_start_real = $this->db->jdate($obj->date_start_real);
541 $this->date_end = $this->db->jdate($obj->date_end);
542 $this->date_end_real = $this->db->jdate($obj->date_end_real);
543
544 $this->tva_tx = $obj->tva_tx;
545 $this->vat_src_code = $obj->vat_src_code;
546 $this->localtax1_tx = $obj->localtax1_tx;
547 $this->localtax2_tx = $obj->localtax2_tx;
548 $this->localtax1_type = $obj->localtax1_type;
549 $this->localtax2_type = $obj->localtax2_type;
550 $this->qty = $obj->qty;
551 $this->remise_percent = $obj->remise_percent;
552 $this->fk_remise_except = $obj->fk_remise_except;
553 $this->subprice = $obj->subprice;
554 $this->total_ht = $obj->total_ht;
555 $this->total_tva = $obj->total_tva;
556 $this->total_localtax1 = $obj->total_localtax1;
557 $this->total_localtax2 = $obj->total_localtax2;
558 $this->total_ttc = $obj->total_ttc;
559 $this->info_bits = $obj->info_bits;
560 $this->fk_user_author = $obj->fk_user_author;
561 $this->fk_user_ouverture = $obj->fk_user_ouverture;
562 $this->fk_user_cloture = $obj->fk_user_cloture;
563 $this->commentaire = $obj->commentaire;
564 $this->fk_fournprice = $obj->fk_fournprice;
565
566 $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->fk_fournprice, $obj->pa_ht);
567 $this->pa_ht = $marginInfos[0];
568 $this->fk_unit = $obj->fk_unit;
569
570 $this->extraparams = !empty($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array();
571
572 $this->rang = $obj->rang;
573
574 $this->fetch_optionals();
575 }
576
577 $this->db->free($resql);
578
579 return 1;
580 } else {
581 $this->error = "Error ".$this->db->lasterror();
582 return -1;
583 }
584 }
585
586
594 public function update($user, $notrigger = 0)
595 {
596 global $mysoc;
597
598 $error = 0;
599
600 // Clean parameters
601 $this->fk_contrat = (int) $this->fk_contrat;
602 $this->fk_product = (int) $this->fk_product;
603 $this->statut = (int) $this->statut;
604 $this->label = trim($this->label);
605 $this->description = trim($this->description);
606 $this->vat_src_code = trim($this->vat_src_code);
607 $this->tva_tx = trim((string) $this->tva_tx);
608 $this->localtax1_tx = trim($this->localtax1_tx);
609 $this->localtax2_tx = trim($this->localtax2_tx);
610 $this->qty = (float) $this->qty;
611 $this->remise_percent = trim((string) $this->remise_percent);
612 $this->fk_remise_except = (int) $this->fk_remise_except;
613 $this->subprice = (float) price2num($this->subprice);
614 $this->info_bits = (int) $this->info_bits;
615 $this->fk_user_author = (int) $this->fk_user_author;
616 $this->fk_user_ouverture = (int) $this->fk_user_ouverture;
617 $this->fk_user_cloture = (int) $this->fk_user_cloture;
618 $this->commentaire = trim($this->commentaire);
619 $this->rang = (int) $this->rang;
620 if (empty($this->subprice)) {
621 $this->subprice = 0;
622 }
623 if (empty($this->total_ht)) {
624 $this->total_ht = 0;
625 }
626 if (empty($this->total_tva)) {
627 $this->total_tva = 0;
628 }
629 if (empty($this->total_ttc)) {
630 $this->total_ttc = 0;
631 }
632 if (empty($this->localtax1_tx)) {
633 $this->localtax1_tx = 0;
634 }
635 if (empty($this->localtax2_tx)) {
636 $this->localtax2_tx = 0;
637 }
638 if (empty($this->remise_percent)) {
639 $this->remise_percent = 0;
640 }
641
642 // Calculation of the gross total (TTC) and VAT for the line from qty, pu, remise_percent and txtva
643 // VERY IMPORTANT: It's at the time of line insertion that we must store the net, VAT, and gross amounts,
644 // and this is done at the line level, which has its own VAT rate
645 $localtaxes_type = getLocalTaxesFromRate($this->tva_tx, 0, $this->thirdparty, $mysoc);
646
647 $tabprice = calcul_price_total($this->qty, $this->subprice, $this->remise_percent, (float) $this->tva_tx, $this->localtax1_tx, $this->localtax2_tx, 0, 'HT', 0, 1, $mysoc, $localtaxes_type);
648 $this->total_ht = (float) $tabprice[0];
649 $this->total_tva = (float) $tabprice[1];
650 $this->total_ttc = (float) $tabprice[2];
651 $this->total_localtax1 = (float) $tabprice[9];
652 $this->total_localtax2 = (float) $tabprice[10];
653
654 if (empty($this->pa_ht)) {
655 $this->pa_ht = 0;
656 }
657
658 // if buy price not defined, define buyprice as configured in margin admin
659 if ($this->pa_ht == 0) {
660 $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
661 if ($result < 0) {
662 return -1;
663 } else {
664 $this->pa_ht = $result;
665 }
666 }
667
668 // $this->oldcopy should have been set by the caller of update (here properties were already modified)
669 if (empty($this->oldcopy)) {
670 dol_syslog("this->oldcopy should have been set by the caller of update (here properties were already modified)", LOG_WARNING);
671 $this->oldcopy = dol_clone($this, 2);
672 }
673
674 $this->db->begin();
675
676 // Update request
677 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET";
678 $sql .= " fk_contrat = ".((int) $this->fk_contrat).",";
679 $sql .= " fk_product = ".($this->fk_product ? ((int) $this->fk_product) : 'null').",";
680 $sql .= " statut = ".((int) $this->statut).",";
681 $sql .= " label = '".$this->db->escape($this->label)."',";
682 $sql .= " description = '".$this->db->escape($this->description)."',";
683 $sql .= " date_commande = ".($this->date_commande != '' ? "'".$this->db->idate($this->date_commande)."'" : "null").",";
684 $sql .= " date_ouverture_prevue = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null").",";
685 $sql .= " date_ouverture = ".($this->date_start_real != '' ? "'".$this->db->idate($this->date_start_real)."'" : "null").",";
686 $sql .= " date_fin_validite = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null").",";
687 $sql .= " date_cloture = ".($this->date_end_real != '' ? "'".$this->db->idate($this->date_end_real)."'" : "null").",";
688 $sql .= " vat_src_code = '".$this->db->escape($this->vat_src_code)."',";
689 $sql .= " tva_tx = ".price2num($this->tva_tx).",";
690 $sql .= " localtax1_tx = ".price2num($this->localtax1_tx).",";
691 $sql .= " localtax2_tx = ".price2num($this->localtax2_tx).",";
692 $sql .= " qty = ".price2num($this->qty).",";
693 $sql .= " remise_percent = ".price2num($this->remise_percent).",";
694 $sql .= " fk_remise_except = ".($this->fk_remise_except > 0 ? $this->fk_remise_except : "null").",";
695 $sql .= " subprice = ".($this->subprice != '' ? $this->subprice : "null").",";
696 $sql .= " total_ht = ".((float) $this->total_ht).",";
697 $sql .= " total_tva = ".((float) $this->total_tva).",";
698 $sql .= " total_localtax1 = ".((float) $this->total_localtax1).",";
699 $sql .= " total_localtax2 = ".((float) $this->total_localtax2).",";
700 $sql .= " total_ttc = ".((float) $this->total_ttc).",";
701 $sql .= " fk_product_fournisseur_price = ".(!empty($this->fk_fournprice) ? $this->fk_fournprice : "NULL").",";
702 $sql .= " buy_price_ht = '".price2num($this->pa_ht)."',";
703 $sql .= " info_bits = '".$this->db->escape((string) $this->info_bits)."',";
704 $sql .= " fk_user_author = ".($this->fk_user_author >= 0 ? $this->fk_user_author : "NULL").",";
705 $sql .= " fk_user_ouverture = ".($this->fk_user_ouverture > 0 ? $this->fk_user_ouverture : "NULL").",";
706 $sql .= " fk_user_cloture = ".($this->fk_user_cloture > 0 ? $this->fk_user_cloture : "NULL").",";
707 $sql .= " commentaire = '".$this->db->escape($this->commentaire)."',";
708 $sql .= " fk_unit = ".(!$this->fk_unit ? 'NULL' : ((int) $this->fk_unit)).",";
709 $sql .= " rang = ".(empty($this->rang) ? '0' : ((int) $this->rang));
710 $sql .= " WHERE rowid = ".((int) $this->id);
711
712 dol_syslog(get_class($this)."::update", LOG_DEBUG);
713 $resql = $this->db->query($sql);
714 if (!$resql) {
715 $this->error = "Error ".$this->db->lasterror();
716 $error++;
717 }
718
719 if (!$error) { // For avoid conflicts if trigger used
720 $result = $this->insertExtraFields();
721 if ($result < 0) {
722 $error++;
723 }
724 }
725
726 // If we change a planned date (start or end) of one contract line, sync dates for all other services too
727 if (!$error && getDolGlobalString('CONTRACT_SYNC_PLANNED_DATE_OF_SERVICES')) {
728 dol_syslog(get_class($this)."::update CONTRACT_SYNC_PLANNED_DATE_OF_SERVICES is on so we update date for all lines", LOG_DEBUG);
729
730 if ($this->date_start != $this->oldcopy->date_start) {
731 $sql = 'UPDATE '.MAIN_DB_PREFIX.'contratdet SET';
732 $sql .= " date_ouverture_prevue = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
733 $sql .= " WHERE fk_contrat = ".((int) $this->fk_contrat);
734
735 $resql = $this->db->query($sql);
736 if (!$resql) {
737 $error++;
738 $this->error = "Error ".$this->db->lasterror();
739 }
740 }
741 if ($this->date_end != $this->oldcopy->date_end) {
742 $sql = 'UPDATE '.MAIN_DB_PREFIX.'contratdet SET';
743 $sql .= " date_fin_validite = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
744 $sql .= " WHERE fk_contrat = ".((int) $this->fk_contrat);
745
746 $resql = $this->db->query($sql);
747 if (!$resql) {
748 $error++;
749 $this->error = "Error ".$this->db->lasterror();
750 }
751 }
752 }
753
754 if (!$error && !$notrigger) {
755 // Call trigger
756 $result = $this->call_trigger('LINECONTRACT_MODIFY', $user);
757 if ($result < 0) {
758 $error++;
759 $this->db->rollback();
760 }
761 // End call triggers
762 }
763
764 if (!$error) {
765 $this->db->commit();
766 return 1;
767 } else {
768 $this->db->rollback();
769 $this->errors[] = $this->error;
770 return -1;
771 }
772 }
773
774
775 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
782 public function update_total()
783 {
784 // phpcs:enable
785 $this->db->begin();
786
787 // Update line in database
788 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET";
789 $sql .= " total_ht=".price2num($this->total_ht, 'MT');
790 $sql .= ",total_tva=".price2num($this->total_tva, 'MT');
791 $sql .= ",total_localtax1=".price2num($this->total_localtax1, 'MT');
792 $sql .= ",total_localtax2=".price2num($this->total_localtax2, 'MT');
793 $sql .= ",total_ttc=".price2num($this->total_ttc, 'MT');
794 $sql .= " WHERE rowid = ".((int) $this->id);
795
796 dol_syslog(get_class($this)."::update_total", LOG_DEBUG);
797
798 $resql = $this->db->query($sql);
799 if ($resql) {
800 $this->db->commit();
801 return 1;
802 } else {
803 $this->error = $this->db->error();
804 $this->db->rollback();
805 return -2;
806 }
807 }
808
809
816 public function insert($notrigger = 0)
817 {
818 global $user;
819
820 $error = 0;
821
822 // Insertion dans la base
823 $sql = "INSERT INTO ".MAIN_DB_PREFIX."contratdet";
824 $sql .= " (fk_contrat, label, description, fk_product, qty, vat_src_code, tva_tx,";
825 $sql .= " localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, remise_percent, subprice,";
826 $sql .= " total_ht, total_tva, total_localtax1, total_localtax2, total_ttc,";
827 $sql .= " info_bits,";
828 $sql .= " rang,";
829 $sql .= " fk_product_fournisseur_price, buy_price_ht";
830 if ($this->date_start > 0) {
831 $sql .= ",date_ouverture_prevue";
832 }
833 if ($this->date_end > 0) {
834 $sql .= ",date_fin_validite";
835 }
836 $sql .= ") VALUES ($this->fk_contrat, '', '".$this->db->escape($this->description)."',";
837 $sql .= ($this->fk_product > 0 ? $this->fk_product : "null").",";
838 $sql .= " '".$this->db->escape((string) $this->qty)."',";
839 $sql .= " '".$this->db->escape($this->vat_src_code)."',";
840 $sql .= " '".$this->db->escape($this->tva_tx)."',";
841 $sql .= " '".$this->db->escape($this->localtax1_tx)."',";
842 $sql .= " '".$this->db->escape($this->localtax2_tx)."',";
843 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
844 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
845 $sql .= " ".price2num($this->remise_percent).",".price2num($this->subprice).",";
846 $sql .= " ".price2num($this->total_ht).",".price2num($this->total_tva).",".price2num($this->total_localtax1).",".price2num($this->total_localtax2).",".price2num($this->total_ttc).",";
847 $sql .= " '".$this->db->escape((string) $this->info_bits)."',";
848 $sql .= " ".(empty($this->rang) ? '0' : (int) $this->rang).",";
849 if ($this->fk_fournprice > 0) {
850 $sql .= ' '.((int) $this->fk_fournprice).',';
851 } else {
852 $sql .= ' null,';
853 }
854 if ($this->pa_ht > 0) {
855 $sql .= ' '.((float) price2num($this->pa_ht));
856 } else {
857 $sql .= ' null';
858 }
859 if ($this->date_start > 0) {
860 $sql .= ",'".$this->db->idate($this->date_start)."'";
861 }
862 if ($this->date_end > 0) {
863 $sql .= ",'".$this->db->idate($this->date_end)."'";
864 }
865 $sql .= ")";
866
867 dol_syslog(get_class($this)."::insert", LOG_DEBUG);
868
869 $resql = $this->db->query($sql);
870 if ($resql) {
871 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'contratdet');
872
873 // Insert of extrafields
874 $result = $this->insertExtraFields();
875 if ($result < 0) {
876 $this->db->rollback();
877 return -1;
878 }
879
880 if (!$notrigger) {
881 // Call trigger
882 $result = $this->call_trigger('LINECONTRACT_INSERT', $user);
883 if ($result < 0) {
884 $this->db->rollback();
885 return -1;
886 }
887 // End call triggers
888 }
889
890 $this->db->commit();
891 return 1;
892 } else {
893 $this->db->rollback();
894 $this->error = $this->db->error()." sql=".$sql;
895 return -1;
896 }
897 }
898
899 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
909 public function active_line($user, $date, $date_end = '', $comment = '')
910 {
911 // phpcs:enable
912 $error = 0;
913
914 $this->db->begin();
915
916 $this->statut = ContratLigne::STATUS_OPEN;
917 $this->status = ContratLigne::STATUS_OPEN;
918 $this->date_start_real = $date;
919 $this->date_end = $date_end;
920 $this->fk_user_ouverture = $user->id;
921 $this->date_end_real = null;
922 $this->commentaire = $comment;
923
924 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET statut = ".((int) $this->status).",";
925 $sql .= " date_ouverture = ".(dol_strlen((string) $this->date_start_real) != 0 ? "'".$this->db->idate($this->date_start_real)."'" : "null").",";
926 if ($date_end >= 0) {
927 $sql .= " date_fin_validite = ".(dol_strlen($this->date_end) != 0 ? "'".$this->db->idate($this->date_end)."'" : "null").",";
928 }
929 $sql .= " fk_user_ouverture = ".((int) $this->fk_user_ouverture).",";
930 $sql .= " date_cloture = null,";
931 $sql .= " commentaire = '".$this->db->escape($comment)."'";
932 $sql .= " WHERE rowid = ".((int) $this->id)." AND (statut = ".ContratLigne::STATUS_INITIAL." OR statut = ".ContratLigne::STATUS_CLOSED.")";
933
934 dol_syslog(get_class($this)."::active_line", LOG_DEBUG);
935 $resql = $this->db->query($sql);
936 if ($resql) {
937 if ($date_end >= 0) {
938 // Update column llx_contrat.denormalized_lower_panned_end_date with next expiration date of an open contract
939 $sqltoupdatecontract = "UPDATE ".MAIN_DB_PREFIX."contrat";
940 $sqltoupdatecontract .= " SET denormalized_lower_planned_end_date = (SELECT MIN(date_fin_validite) FROM ".MAIN_DB_PREFIX."contratdet as cd WHERE cd.fk_contrat = ".((int) $this->fk_contrat)." AND cd.statut = ".ContratLigne::STATUS_OPEN.")";
941 $sqltoupdatecontract .= " WHERE rowid = ".((int) $this->fk_contrat);
942 $resqltoupdatecontract = $this->db->query($sqltoupdatecontract);
943 if (!$resqltoupdatecontract) {
944 $this->error = $this->db->lasterror();
945 $this->db->rollback();
946 return -1;
947 }
948 }
949
950 // Call trigger
951 $result = $this->call_trigger('LINECONTRACT_ACTIVATE', $user);
952 if ($result < 0) {
953 $error++;
954 }
955 // End call triggers
956
957 if (!$error) {
958 $this->db->commit();
959 return 1;
960 } else {
961 $this->db->rollback();
962 return -1;
963 }
964 } else {
965 $this->error = $this->db->lasterror();
966 $this->db->rollback();
967 return -1;
968 }
969 }
970
971 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
981 public function close_line($user, $date_end_real, $comment = '', $notrigger = 0)
982 {
983 // phpcs:enable
984 $this->date_cloture = $date_end_real;
985 $this->date_end_real = $date_end_real;
986 $this->user_closing_id = $user->id;
987 $this->commentaire = $comment;
988
989 $error = 0;
990
991 // statut actif : 4
992
993 $this->db->begin();
994
995 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET statut = ".((int) ContratLigne::STATUS_CLOSED).",";
996 $sql .= " date_cloture = '".$this->db->idate($date_end_real)."',";
997 $sql .= " fk_user_cloture = ".((int) $user->id).",";
998 $sql .= " commentaire = '".$this->db->escape($comment)."'";
999 $sql .= " WHERE rowid = ".((int) $this->id)." AND statut <> ".((int) ContratLigne::STATUS_CLOSED);
1000
1001 $resql = $this->db->query($sql);
1002 if ($resql) {
1003 // Update column llx_contrat.denormalized_lower_panned_end_date with next expiration date of an open contract
1004 $sqltoupdatecontract = "UPDATE ".MAIN_DB_PREFIX."contrat";
1005 $sqltoupdatecontract .= " SET denormalized_lower_planned_end_date = (SELECT MIN(date_fin_validite) FROM ".MAIN_DB_PREFIX."contratdet as cd WHERE cd.fk_contrat = ".((int) $this->fk_contrat)." AND cd.statut = ".ContratLigne::STATUS_OPEN.")";
1006 $sqltoupdatecontract .= " WHERE rowid = ".((int) $this->fk_contrat);
1007 $resqltoupdatecontract = $this->db->query($sqltoupdatecontract);
1008 if (!$resqltoupdatecontract) {
1009 $this->error = $this->db->lasterror();
1010 $this->db->rollback();
1011 return -1;
1012 }
1013
1014 if (!$notrigger) {
1015 // Call trigger
1016 $result = $this->call_trigger('LINECONTRACT_CLOSE', $user);
1017 if ($result < 0) {
1018 $error++;
1019 $this->db->rollback();
1020 return -1;
1021 }
1022 // End call triggers
1023 }
1024
1025 $this->db->commit();
1026 return 1;
1027 } else {
1028 $this->error = $this->db->lasterror();
1029 $this->db->rollback();
1030 return -1;
1031 }
1032 }
1033}
$object ref
Definition info.php:90
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage lines of contracts.
active_line($user, $date, $date_end='', $comment='')
Activate a contract line.
getLibStatut($mode)
Return label of this contract line status.
insert($notrigger=0)
Inserts a contrat line into database.
fetch($id, $ref='')
Load object in memory from database.
close_line($user, $date_end_real, $comment='', $notrigger=0)
Close a contract line.
static LibStatut($status, $mode, $expired=-1, $moreatt='', $morelabel='')
Return label of a contract line status.
update($user, $notrigger=0)
Update database for contract line.
update_total()
Update in database the fields total_xxx of lines Used by migration process.
__construct($db)
Constructor.
getTooltipContentArray($params)
getTooltipContentArray
getNomUrl($withpicto=0, $maxlength=0)
Return clickable name (with picto eventually) for ContratLigne.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:168
global $mysoc
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_now($mode='gmt')
Return date for now.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getMarginInfos($pv_ht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $pa_ht)
Return an array with margins information of a line.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller=null, $localtaxes_array=[], $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:90
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130