dolibarr 23.0.3
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-2025 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 // Calcul du total TTC et de la TVA pour la ligne a partir de
643 // qty, pu, remise_percent et txtva
644 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
645 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
646 $localtaxes_type = getLocalTaxesFromRate($this->tva_tx, 0, $this->thirdparty, $mysoc);
647
648 $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);
649 $this->total_ht = (float) $tabprice[0];
650 $this->total_tva = (float) $tabprice[1];
651 $this->total_ttc = (float) $tabprice[2];
652 $this->total_localtax1 = (float) $tabprice[9];
653 $this->total_localtax2 = (float) $tabprice[10];
654
655 if (empty($this->pa_ht)) {
656 $this->pa_ht = 0;
657 }
658
659 // if buy price not defined, define buyprice as configured in margin admin
660 if ($this->pa_ht == 0) {
661 $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
662 if ($result < 0) {
663 return -1;
664 } else {
665 $this->pa_ht = $result;
666 }
667 }
668
669 // $this->oldcopy should have been set by the caller of update (here properties were already modified)
670 if (empty($this->oldcopy)) {
671 dol_syslog("this->oldcopy should have been set by the caller of update (here properties were already modified)", LOG_WARNING);
672 $this->oldcopy = dol_clone($this, 2);
673 }
674
675 $this->db->begin();
676
677 // Update request
678 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET";
679 $sql .= " fk_contrat = ".((int) $this->fk_contrat).",";
680 $sql .= " fk_product = ".($this->fk_product ? ((int) $this->fk_product) : 'null').",";
681 $sql .= " statut = ".((int) $this->statut).",";
682 $sql .= " label = '".$this->db->escape($this->label)."',";
683 $sql .= " description = '".$this->db->escape($this->description)."',";
684 $sql .= " date_commande = ".($this->date_commande != '' ? "'".$this->db->idate($this->date_commande)."'" : "null").",";
685 $sql .= " date_ouverture_prevue = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null").",";
686 $sql .= " date_ouverture = ".($this->date_start_real != '' ? "'".$this->db->idate($this->date_start_real)."'" : "null").",";
687 $sql .= " date_fin_validite = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null").",";
688 $sql .= " date_cloture = ".($this->date_end_real != '' ? "'".$this->db->idate($this->date_end_real)."'" : "null").",";
689 $sql .= " vat_src_code = '".$this->db->escape($this->vat_src_code)."',";
690 $sql .= " tva_tx = ".price2num($this->tva_tx).",";
691 $sql .= " localtax1_tx = ".price2num($this->localtax1_tx).",";
692 $sql .= " localtax2_tx = ".price2num($this->localtax2_tx).",";
693 $sql .= " qty = ".price2num($this->qty).",";
694 $sql .= " remise_percent = ".price2num($this->remise_percent).",";
695 $sql .= " fk_remise_except = ".($this->fk_remise_except > 0 ? $this->fk_remise_except : "null").",";
696 $sql .= " subprice = ".($this->subprice != '' ? $this->subprice : "null").",";
697 $sql .= " total_ht = ".((float) $this->total_ht).",";
698 $sql .= " total_tva = ".((float) $this->total_tva).",";
699 $sql .= " total_localtax1 = ".((float) $this->total_localtax1).",";
700 $sql .= " total_localtax2 = ".((float) $this->total_localtax2).",";
701 $sql .= " total_ttc = ".((float) $this->total_ttc).",";
702 $sql .= " fk_product_fournisseur_price = ".(!empty($this->fk_fournprice) ? $this->fk_fournprice : "NULL").",";
703 $sql .= " buy_price_ht = '".price2num($this->pa_ht)."',";
704 $sql .= " info_bits = '".$this->db->escape((string) $this->info_bits)."',";
705 $sql .= " fk_user_author = ".($this->fk_user_author >= 0 ? $this->fk_user_author : "NULL").",";
706 $sql .= " fk_user_ouverture = ".($this->fk_user_ouverture > 0 ? $this->fk_user_ouverture : "NULL").",";
707 $sql .= " fk_user_cloture = ".($this->fk_user_cloture > 0 ? $this->fk_user_cloture : "NULL").",";
708 $sql .= " commentaire = '".$this->db->escape($this->commentaire)."',";
709 $sql .= " fk_unit = ".(!$this->fk_unit ? 'NULL' : $this->fk_unit).",";
710 $sql .= " rang = ".(empty($this->rang) ? '0' : (int) $this->rang);
711 $sql .= " WHERE rowid = ".((int) $this->id);
712
713 dol_syslog(get_class($this)."::update", LOG_DEBUG);
714 $resql = $this->db->query($sql);
715 if (!$resql) {
716 $this->error = "Error ".$this->db->lasterror();
717 $error++;
718 }
719
720 if (!$error) { // For avoid conflicts if trigger used
721 $result = $this->insertExtraFields();
722 if ($result < 0) {
723 $error++;
724 }
725 }
726
727 // If we change a planned date (start or end) of one contract line, sync dates for all other services too
728 if (!$error && getDolGlobalString('CONTRACT_SYNC_PLANNED_DATE_OF_SERVICES')) {
729 dol_syslog(get_class($this)."::update CONTRACT_SYNC_PLANNED_DATE_OF_SERVICES is on so we update date for all lines", LOG_DEBUG);
730
731 if ($this->date_start != $this->oldcopy->date_start) {
732 $sql = 'UPDATE '.MAIN_DB_PREFIX.'contratdet SET';
733 $sql .= " date_ouverture_prevue = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
734 $sql .= " WHERE fk_contrat = ".((int) $this->fk_contrat);
735
736 $resql = $this->db->query($sql);
737 if (!$resql) {
738 $error++;
739 $this->error = "Error ".$this->db->lasterror();
740 }
741 }
742 if ($this->date_end != $this->oldcopy->date_end) {
743 $sql = 'UPDATE '.MAIN_DB_PREFIX.'contratdet SET';
744 $sql .= " date_fin_validite = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
745 $sql .= " WHERE fk_contrat = ".((int) $this->fk_contrat);
746
747 $resql = $this->db->query($sql);
748 if (!$resql) {
749 $error++;
750 $this->error = "Error ".$this->db->lasterror();
751 }
752 }
753 }
754
755 if (!$error && !$notrigger) {
756 // Call trigger
757 $result = $this->call_trigger('LINECONTRACT_MODIFY', $user);
758 if ($result < 0) {
759 $error++;
760 $this->db->rollback();
761 }
762 // End call triggers
763 }
764
765 if (!$error) {
766 $this->db->commit();
767 return 1;
768 } else {
769 $this->db->rollback();
770 $this->errors[] = $this->error;
771 return -1;
772 }
773 }
774
775
776 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
783 public function update_total()
784 {
785 // phpcs:enable
786 $this->db->begin();
787
788 // Mise a jour ligne en base
789 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET";
790 $sql .= " total_ht=".price2num($this->total_ht, 'MT');
791 $sql .= ",total_tva=".price2num($this->total_tva, 'MT');
792 $sql .= ",total_localtax1=".price2num($this->total_localtax1, 'MT');
793 $sql .= ",total_localtax2=".price2num($this->total_localtax2, 'MT');
794 $sql .= ",total_ttc=".price2num($this->total_ttc, 'MT');
795 $sql .= " WHERE rowid = ".((int) $this->id);
796
797 dol_syslog(get_class($this)."::update_total", LOG_DEBUG);
798
799 $resql = $this->db->query($sql);
800 if ($resql) {
801 $this->db->commit();
802 return 1;
803 } else {
804 $this->error = $this->db->error();
805 $this->db->rollback();
806 return -2;
807 }
808 }
809
810
817 public function insert($notrigger = 0)
818 {
819 global $user;
820
821 $error = 0;
822
823 // Insertion dans la base
824 $sql = "INSERT INTO ".MAIN_DB_PREFIX."contratdet";
825 $sql .= " (fk_contrat, label, description, fk_product, qty, vat_src_code, tva_tx,";
826 $sql .= " localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, remise_percent, subprice,";
827 $sql .= " total_ht, total_tva, total_localtax1, total_localtax2, total_ttc,";
828 $sql .= " info_bits,";
829 $sql .= " rang,";
830 $sql .= " fk_product_fournisseur_price, buy_price_ht";
831 if ($this->date_start > 0) {
832 $sql .= ",date_ouverture_prevue";
833 }
834 if ($this->date_end > 0) {
835 $sql .= ",date_fin_validite";
836 }
837 $sql .= ") VALUES ($this->fk_contrat, '', '".$this->db->escape($this->description)."',";
838 $sql .= ($this->fk_product > 0 ? $this->fk_product : "null").",";
839 $sql .= " '".$this->db->escape((string) $this->qty)."',";
840 $sql .= " '".$this->db->escape($this->vat_src_code)."',";
841 $sql .= " '".$this->db->escape($this->tva_tx)."',";
842 $sql .= " '".$this->db->escape($this->localtax1_tx)."',";
843 $sql .= " '".$this->db->escape($this->localtax2_tx)."',";
844 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
845 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
846 $sql .= " ".price2num($this->remise_percent).",".price2num($this->subprice).",";
847 $sql .= " ".price2num($this->total_ht).",".price2num($this->total_tva).",".price2num($this->total_localtax1).",".price2num($this->total_localtax2).",".price2num($this->total_ttc).",";
848 $sql .= " '".$this->db->escape((string) $this->info_bits)."',";
849 $sql .= " ".(empty($this->rang) ? '0' : (int) $this->rang).",";
850 if ($this->fk_fournprice > 0) {
851 $sql .= ' '.((int) $this->fk_fournprice).',';
852 } else {
853 $sql .= ' null,';
854 }
855 if ($this->pa_ht > 0) {
856 $sql .= ' '.((float) price2num($this->pa_ht));
857 } else {
858 $sql .= ' null';
859 }
860 if ($this->date_start > 0) {
861 $sql .= ",'".$this->db->idate($this->date_start)."'";
862 }
863 if ($this->date_end > 0) {
864 $sql .= ",'".$this->db->idate($this->date_end)."'";
865 }
866 $sql .= ")";
867
868 dol_syslog(get_class($this)."::insert", LOG_DEBUG);
869
870 $resql = $this->db->query($sql);
871 if ($resql) {
872 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'contratdet');
873
874 // Insert of extrafields
875 $result = $this->insertExtraFields();
876 if ($result < 0) {
877 $this->db->rollback();
878 return -1;
879 }
880
881 if (!$notrigger) {
882 // Call trigger
883 $result = $this->call_trigger('LINECONTRACT_INSERT', $user);
884 if ($result < 0) {
885 $this->db->rollback();
886 return -1;
887 }
888 // End call triggers
889 }
890
891 $this->db->commit();
892 return 1;
893 } else {
894 $this->db->rollback();
895 $this->error = $this->db->error()." sql=".$sql;
896 return -1;
897 }
898 }
899
900 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
910 public function active_line($user, $date, $date_end = '', $comment = '')
911 {
912 // phpcs:enable
913 $error = 0;
914
915 $this->db->begin();
916
917 $this->statut = ContratLigne::STATUS_OPEN;
918 $this->status = ContratLigne::STATUS_OPEN;
919 $this->date_start_real = $date;
920 $this->date_end = $date_end;
921 $this->fk_user_ouverture = $user->id;
922 $this->date_end_real = null;
923 $this->commentaire = $comment;
924
925 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET statut = ".((int) $this->status).",";
926 $sql .= " date_ouverture = ".(dol_strlen((string) $this->date_start_real) != 0 ? "'".$this->db->idate($this->date_start_real)."'" : "null").",";
927 if ($date_end >= 0) {
928 $sql .= " date_fin_validite = ".(dol_strlen($this->date_end) != 0 ? "'".$this->db->idate($this->date_end)."'" : "null").",";
929 }
930 $sql .= " fk_user_ouverture = ".((int) $this->fk_user_ouverture).",";
931 $sql .= " date_cloture = null,";
932 $sql .= " commentaire = '".$this->db->escape($comment)."'";
933 $sql .= " WHERE rowid = ".((int) $this->id)." AND (statut = ".ContratLigne::STATUS_INITIAL." OR statut = ".ContratLigne::STATUS_CLOSED.")";
934
935 dol_syslog(get_class($this)."::active_line", LOG_DEBUG);
936 $resql = $this->db->query($sql);
937 if ($resql) {
938 if ($date_end >= 0) {
939 // Update column llx_contrat.denormalized_lower_panned_end_date with next expiration date of an open contract
940 $sqltoupdatecontract = "UPDATE ".MAIN_DB_PREFIX."contrat";
941 $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.")";
942 $sqltoupdatecontract .= " WHERE rowid = ".((int) $this->fk_contrat);
943 $resqltoupdatecontract = $this->db->query($sqltoupdatecontract);
944 if (!$resqltoupdatecontract) {
945 $this->error = $this->db->lasterror();
946 $this->db->rollback();
947 return -1;
948 }
949 }
950
951 // Call trigger
952 $result = $this->call_trigger('LINECONTRACT_ACTIVATE', $user);
953 if ($result < 0) {
954 $error++;
955 }
956 // End call triggers
957
958 if (!$error) {
959 $this->db->commit();
960 return 1;
961 } else {
962 $this->db->rollback();
963 return -1;
964 }
965 } else {
966 $this->error = $this->db->lasterror();
967 $this->db->rollback();
968 return -1;
969 }
970 }
971
972 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
982 public function close_line($user, $date_end_real, $comment = '', $notrigger = 0)
983 {
984 // phpcs:enable
985 $this->date_cloture = $date_end_real;
986 $this->date_end_real = $date_end_real;
987 $this->user_closing_id = $user->id;
988 $this->commentaire = $comment;
989
990 $error = 0;
991
992 // statut actif : 4
993
994 $this->db->begin();
995
996 $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET statut = ".((int) ContratLigne::STATUS_CLOSED).",";
997 $sql .= " date_cloture = '".$this->db->idate($date_end_real)."',";
998 $sql .= " fk_user_cloture = ".((int) $user->id).",";
999 $sql .= " commentaire = '".$this->db->escape($comment)."'";
1000 $sql .= " WHERE rowid = ".((int) $this->id)." AND statut <> ".((int) ContratLigne::STATUS_CLOSED);
1001
1002 $resql = $this->db->query($sql);
1003 if ($resql) {
1004 // Update column llx_contrat.denormalized_lower_panned_end_date with next expiration date of an open contract
1005 $sqltoupdatecontract = "UPDATE ".MAIN_DB_PREFIX."contrat";
1006 $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.")";
1007 $sqltoupdatecontract .= " WHERE rowid = ".((int) $this->fk_contrat);
1008 $resqltoupdatecontract = $this->db->query($sqltoupdatecontract);
1009 if (!$resqltoupdatecontract) {
1010 $this->error = $this->db->lasterror();
1011 $this->db->rollback();
1012 return -1;
1013 }
1014
1015 if (!$notrigger) {
1016 // Call trigger
1017 $result = $this->call_trigger('LINECONTRACT_CLOSE', $user);
1018 if ($result < 0) {
1019 $error++;
1020 $this->db->rollback();
1021 return -1;
1022 }
1023 // End call triggers
1024 }
1025
1026 $this->db->commit();
1027 return 1;
1028 } else {
1029 $this->error = $this->db->lasterror();
1030 $this->db->rollback();
1031 return -1;
1032 }
1033 }
1034}
$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:171
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.
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.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
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:125