Passed
Push — dev ( f7d146...05f415 )
by Rafael
60:50
created

ContratLigne::update()   F

Complexity

Conditions 43
Paths > 20000

Size

Total Lines 182
Code Lines 130

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 43
eloc 130
nc 268435712
nop 2
dl 0
loc 182
rs 0
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2003       Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2004-2012	Destailleur Laurent		    <[email protected]>
5
 * Copyright (C) 2005-2014	Regis Houssin			    <[email protected]>
6
 * Copyright (C) 2006		Andre Cianfarani		    <[email protected]>
7
 * Copyright (C) 2008		Raphael Bertrand		    <[email protected]>
8
 * Copyright (C) 2010-2016	Juanjo Menent			    <[email protected]>
9
 * Copyright (C) 2013		Christophe Battarel		    <[email protected]>
10
 * Copyright (C) 2013		Florian Henry			    <[email protected]>
11
 * Copyright (C) 2014-2015	Marcos García			    <[email protected]>
12
 * Copyright (C) 2018   	Nicolas ZABOURI			    <[email protected]>
13
 * Copyright (C) 2018-2024  Frédéric France             <[email protected]>
14
 * Copyright (C) 2015-2018	Ferran Marcet			    <[email protected]>
15
 * Copyright (C) 2024		William Mead			    <[email protected]>
16
 * Copyright (C) 2024		MDW							<[email protected]>
17
 * Copyright (C) 2024       Rafael San José             <[email protected]>
18
 *
19
 * This program is free software; you can redistribute it and/or modify
20
 * it under the terms of the GNU General Public License as published by
21
 * the Free Software Foundation; either version 3 of the License, or
22
 * (at your option) any later version.
23
 *
24
 * This program is distributed in the hope that it will be useful,
25
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27
 * GNU General Public License for more details.
28
 *
29
 * You should have received a copy of the GNU General Public License
30
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
31
 */
32
33
namespace Dolibarr\Code\Contrat\Classes;
34
35
use Dolibarr\Core\Base\CommonObjectLine;
36
use DoliDB;
37
38
/**
39
 *  \file       htdocs/contrat/class/contrat.class.php
40
 *  \ingroup    contrat
41
 *  \brief      File of class to manage contracts
42
 */
43
44
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/price.lib.php';
45
require_once constant('DOL_DOCUMENT_ROOT') . '/margin/lib/margins.lib.php';
46
47
/**
48
 *  Class to manage lines of contracts
49
 */
50
class ContratLigne extends CommonObjectLine
51
{
52
    /**
53
     * @var string ID to identify managed object
54
     */
55
    public $element = 'contratdet';
56
57
    /**
58
     * @var string Name of table without prefix where object is stored
59
     */
60
    public $table_element = 'contratdet';
61
62
    /**
63
     * @see CommonObjectLine
64
     */
65
    public $parent_element = 'contrat';
66
67
    /**
68
     * @see CommonObjectLine
69
     */
70
    public $fk_parent_attribute = 'fk_contrat';
71
72
    /**
73
     * @var string  Name to use for 'features' parameter to check module permissions user->rights->feature with restrictedArea().
74
     *              Undefined means same value than $element. Can be use to force a check on another element for example for class of line, we mention here the parent element.
75
     */
76
    public $element_for_permission = 'contrat';
77
78
    /**
79
     * @var int ID
80
     */
81
    public $id;
82
83
    /**
84
     * @var string Ref
85
     */
86
    public $ref;
87
88
    /**
89
     * @var int ID
90
     */
91
    public $fk_contrat;
92
93
    /**
94
     * @var int ID
95
     */
96
    public $fk_product;
97
98
    public $statut; // 0 inactive, 4 active, 5 closed
99
    public $type; // 0 for product, 1 for service
100
101
    /**
102
     * @var string
103
     * @deprecated
104
     */
105
    public $label;
106
107
    /**
108
     * @var string
109
     * @deprecated
110
     */
111
    public $libelle;
112
113
    /**
114
     * @var string description
115
     */
116
    public $description;
117
118
    public $product_type; // 0 for product, 1 for service
119
    public $product_ref;
120
    public $product_label;
121
122
    public $date_commande;
123
124
    public $date_start; // date start planned
125
    public $date_start_real; // date start real
126
    public $date_end; // date end planned
127
    public $date_end_real; // date end real
128
129
    public $tva_tx;
130
    public $vat_src_code;
131
    public $localtax1_tx;
132
    public $localtax2_tx;
133
    public $localtax1_type; // Local tax 1 type
134
    public $localtax2_type; // Local tax 2 type
135
    public $qty;
136
    public $remise_percent;
137
    public $remise;
138
139
    /**
140
     * @var int ID
141
     */
142
    public $fk_remise_except;
143
144
    /**
145
     * Unit price before taxes
146
     * @var float
147
     */
148
    public $subprice;
149
150
    /**
151
     * @var float
152
     * @deprecated Use $price_ht instead
153
     * @see $price_ht
154
     */
155
    public $price;
156
157
    /**
158
     * @var float price without tax
159
     */
160
    public $price_ht;
161
162
    public $total_ht;
163
    public $total_tva;
164
    public $total_localtax1;
165
    public $total_localtax2;
166
    public $total_ttc;
167
168
    /**
169
     * @var int     ID
170
     */
171
    public $fk_fournprice;
172
173
    public $pa_ht;
174
175
    /**
176
     * @var int     Info bits
177
     */
178
    public $info_bits;
179
180
    /**
181
     * @var int     ID of user that insert the service
182
     */
183
    public $fk_user_author;
184
185
    /**
186
     * @var int     ID of user opening the service
187
     */
188
    public $fk_user_ouverture;
189
190
    /**
191
     * @var int     ID of user closing the service
192
     */
193
    public $fk_user_cloture;
194
195
    /**
196
     * @var string  Comment
197
     */
198
    public $commentaire;
199
200
201
    /**
202
     * @var int line rank
203
     */
204
    public $rang = 0;
205
206
207
    const STATUS_INITIAL = 0;
208
    const STATUS_OPEN = 4;
209
    const STATUS_CLOSED = 5;
210
211
212
    // BEGIN MODULEBUILDER PROPERTIES
213
    /**
214
     * @var array<string,array{type:string,label:string,enabled:int<0,2>|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array<int,string>,comment?:string}>  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string,array{type:...ring>,comment?:string}> at position 16 could not be parsed: Expected '}' at position 16, but found 'int'.
Loading history...
215
     */
216
    public $fields = array(
217
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
218
        'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 30, 'index' => 1),
219
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35),
220
        'qty' => array('type' => 'integer', 'label' => 'Quantity', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'position' => 35, 'isameasure' => 1),
221
        'total_ht' => array('type' => 'integer', 'label' => 'AmountHT', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 36, 'isameasure' => 1),
222
        'total_tva' => array('type' => 'integer', 'label' => 'AmountVAT', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 37, 'isameasure' => 1),
223
        'total_ttc' => array('type' => 'integer', 'label' => 'AmountTTC', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 38, 'isameasure' => 1),
224
        //'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
225
        //'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>70),
226
        'fk_contrat' => array('type' => 'integer:Contrat:contrat/class/contrat.class.php', 'label' => 'Contract', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 70),
227
        'fk_product' => array('type' => 'integer:Product:product/class/product.class.php:1', 'label' => 'Product', 'enabled' => 1, 'visible' => -1, 'position' => 75),
228
        //'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>90),
229
        'note_private' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 105),
230
        'note_public' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 110),
231
        //'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>115),
232
        //'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>120),
233
        //'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
234
        'fk_user_ouverture' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserStartingService', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 135),
235
        'fk_user_cloture' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserClosingService', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 135),
236
        'statut' => array('type' => 'smallint(6)', 'label' => 'Statut', 'enabled' => 1, 'visible' => -1, 'position' => 500, 'arrayofkeyval' => array(0 => 'Draft', 4 => 'Open', 5 => 'Closed')),
237
        'rang' => array('type' => 'integer', 'label' => 'Rank', 'enabled' => 1, 'visible' => 0, 'position' => 500, 'default' => '0')
238
    );
239
    // END MODULEBUILDER PROPERTIES
240
241
242
    /**
243
     *  Constructor
244
     *
245
     *  @param      DoliDB      $db      Database handler
246
     */
247
    public function __construct($db)
248
    {
249
        $this->db = $db;
250
    }
251
252
253
    /**
254
     *  Return label of this contract line status
255
     *
256
     *  @param  int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
257
     *  @return string              Label of status
258
     */
259
    public function getLibStatut($mode)
260
    {
261
        return $this->LibStatut($this->statut, $mode, ((!empty($this->date_end)) ? ($this->date_end < dol_now() ? 1 : 0) : -1));
262
    }
263
264
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
265
    /**
266
     *  Return label of a contract line status
267
     *
268
     *  @param  int     $status     Id status
269
     *  @param  int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
270
     *  @param  int     $expired    0=Not expired, 1=Expired, -1=Both or unknown
271
     *  @param  string  $moreatt    More attribute
272
     *  @param  string  $morelabel  More label
273
     *  @return string              Label of status
274
     */
275
    public static function LibStatut($status, $mode, $expired = -1, $moreatt = '', $morelabel = '')
276
    {
277
		// phpcs:enable
278
        global $langs;
279
        $langs->load("contracts");
280
281
        if ($status == self::STATUS_INITIAL) {
282
            $labelStatus = $langs->transnoentities("ServiceStatusInitial");
283
            $labelStatusShort = $langs->transnoentities("ServiceStatusInitial");
284
        } elseif ($status == self::STATUS_OPEN && $expired == -1) {
285
            $labelStatus = $langs->transnoentities("ServiceStatusRunning");
286
            $labelStatusShort = $langs->transnoentities("ServiceStatusRunning");
287
        } elseif ($status == self::STATUS_OPEN && $expired == 0) {
288
            $labelStatus = $langs->transnoentities("ServiceStatusNotLate");
289
            $labelStatusShort = $langs->transnoentities("ServiceStatusNotLateShort");
290
        } elseif ($status == self::STATUS_OPEN && $expired == 1) {
291
            $labelStatus = $langs->transnoentities("ServiceStatusLate");
292
            $labelStatusShort = $langs->transnoentities("ServiceStatusLateShort");
293
        } elseif ($status == self::STATUS_CLOSED) {
294
            $labelStatus = $langs->transnoentities("ServiceStatusClosed");
295
            $labelStatusShort = $langs->transnoentities("ServiceStatusClosed");
296
        }
297
298
        $statusType = 'status' . $status;
299
        if ($status == self::STATUS_OPEN && $expired == 1) {
300
            $statusType = 'status1';
301
        }
302
        if ($status == self::STATUS_CLOSED) {
303
            $statusType = 'status6';
304
        }
305
306
        $params = array();
307
        $reg = array();
308
        if (preg_match('/class="(.*)"/', $moreatt, $reg)) {
309
            $params = array('badgeParams' => array('css' => $reg[1]));
310
        }
311
        return dolGetStatus($labelStatus . ($morelabel ? ' ' . $morelabel : ''), $labelStatusShort . ($morelabel ? ' ' . $morelabel : ''), '', $statusType, $mode, '', $params);
312
    }
313
314
    /**
315
     * getTooltipContentArray
316
     * @param array $params params to construct tooltip data
317
     * @since v18
318
     * @return array
319
     */
320
    public function getTooltipContentArray($params)
321
    {
322
        global $conf, $langs, $user;
323
324
        $datas = [];
325
        $datas['label'] = $langs->trans("ShowContractOfService") . ': ' . $this->label;
326
        if (empty($datas['label'])) {
327
            $datas['label'] = $this->description;
328
        }
329
330
        return $datas;
331
    }
332
333
    /**
334
     *  Return clicable name (with picto eventually) for ContratLigne
335
     *
336
     *  @param  int     $withpicto      0=No picto, 1=Include picto into link, 2=Only picto
337
     *  @param  int     $maxlength      Max length
338
     *  @return string                  Chaine avec URL
339
     */
340
    public function getNomUrl($withpicto = 0, $maxlength = 0)
341
    {
342
        global $langs;
343
344
        $result = '';
345
        $label = $langs->trans("ShowContractOfService") . ': ' . $this->label;
346
        if (empty($label)) {
347
            $label = $this->description;
348
        }
349
        $classfortooltip = 'classfortooltip';
350
        $dataparams = '';
351
        if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
352
            $params = [
353
                'id' => $this->fk_contrat,
354
                'objecttype' => $this->element,
355
            ];
356
            $classfortooltip = 'classforajaxtooltip';
357
            $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"';
358
            $label = '';
359
        }
360
361
        $link = '<a href="' . constant('BASE_URL') . '/contrat/card.php?id=' . $this->fk_contrat . '"';
362
        $link .= ($label ? ' title="' . dol_escape_htmltag($label, 1) . '"' : ' title="tocomplete"');
363
        $link .= $dataparams . ' class="' . $classfortooltip . '">';
364
        $linkend = '</a>';
365
366
        $picto = 'service';
367
        if ($this->type == 0) {
368
            $picto = 'product';
369
        }
370
371
        if ($withpicto) {
372
            $result .= ($link . img_object($label, $picto, $dataparams . ' class="' . $classfortooltip . '"') . $linkend);
373
        }
374
        if ($withpicto && $withpicto != 2) {
375
            $result .= ' ';
376
        }
377
        if ($withpicto != 2) {
378
            $result .= $link . ($this->product_ref ? $this->product_ref . ' ' : '') . ($this->label ? $this->label : $this->description) . $linkend;
379
        }
380
        return $result;
381
    }
382
383
    /**
384
     *  Load object in memory from database
385
     *
386
     *  @param  int     $id         Id object
387
     *  @param  string  $ref        Ref of contract line
388
     *  @return int                 Return integer <0 if KO, >0 if OK
389
     */
390
    public function fetch($id, $ref = '')
391
    {
392
        // Check parameters
393
        if (empty($id) && empty($ref)) {
394
            return -1;
395
        }
396
397
        $sql = "SELECT";
398
        $sql .= " t.rowid,";
399
        $sql .= " t.tms,";
400
        $sql .= " t.fk_contrat,";
401
        $sql .= " t.fk_product,";
402
        $sql .= " t.statut,";
403
        $sql .= " t.label,"; // This field is not used. Only label of product
404
        $sql .= " p.ref as product_ref,";
405
        $sql .= " p.label as product_label,";
406
        $sql .= " p.description as product_desc,";
407
        $sql .= " p.fk_product_type as product_type,";
408
        $sql .= " t.description,";
409
        $sql .= " t.date_commande,";
410
        $sql .= " t.date_ouverture_prevue as date_start,";
411
        $sql .= " t.date_ouverture as date_start_real,";
412
        $sql .= " t.date_fin_validite as date_end,";
413
        $sql .= " t.date_cloture as date_end_real,";
414
        $sql .= " t.tva_tx,";
415
        $sql .= " t.vat_src_code,";
416
        $sql .= " t.localtax1_tx,";
417
        $sql .= " t.localtax2_tx,";
418
        $sql .= " t.localtax1_type,";
419
        $sql .= " t.localtax2_type,";
420
        $sql .= " t.qty,";
421
        $sql .= " t.remise_percent,";
422
        $sql .= " t.remise,";
423
        $sql .= " t.fk_remise_except,";
424
        $sql .= " t.subprice,";
425
        $sql .= " t.price_ht,";
426
        $sql .= " t.total_ht,";
427
        $sql .= " t.total_tva,";
428
        $sql .= " t.total_localtax1,";
429
        $sql .= " t.total_localtax2,";
430
        $sql .= " t.total_ttc,";
431
        $sql .= " t.fk_product_fournisseur_price as fk_fournprice,";
432
        $sql .= " t.buy_price_ht as pa_ht,";
433
        $sql .= " t.info_bits,";
434
        $sql .= " t.fk_user_author,";
435
        $sql .= " t.fk_user_ouverture,";
436
        $sql .= " t.fk_user_cloture,";
437
        $sql .= " t.commentaire,";
438
        $sql .= " t.fk_unit,";
439
        $sql .= " t.rang";
440
        $sql .= " FROM " . MAIN_DB_PREFIX . "contratdet as t LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = t.fk_product";
441
        if ($id) {
442
            $sql .= " WHERE t.rowid = " . ((int) $id);
443
        }
444
        if ($ref) {
445
            $sql .= " WHERE t.rowid = '" . $this->db->escape($ref) . "'";
446
        }
447
448
        dol_syslog(get_only_class($this) . "::fetch", LOG_DEBUG);
449
        $resql = $this->db->query($sql);
450
        if ($resql) {
451
            if ($this->db->num_rows($resql)) {
452
                $obj = $this->db->fetch_object($resql);
453
454
                $this->id    = $obj->rowid;
455
                $this->ref   = $obj->rowid;
456
457
                $this->tms = $this->db->jdate($obj->tms);
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$tms has been deprecated: Use $date_modification ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

457
                /** @scrutinizer ignore-deprecated */ $this->tms = $this->db->jdate($obj->tms);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
Documentation Bug introduced by
It seems like $this->db->jdate($obj->tms) can also be of type string. However, the property $tms is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
458
                $this->fk_contrat = $obj->fk_contrat;
459
                $this->fk_product = $obj->fk_product;
460
                $this->statut = $obj->statut;
461
                $this->product_ref = $obj->product_ref;
462
                $this->product_label = $obj->product_label;
463
                $this->product_type = $obj->product_type;
464
                $this->label = $obj->label; // deprecated. We do not use this field. Only ref and label of product, and description of contract line
465
                $this->description = $obj->description;
466
                $this->date_commande = $this->db->jdate($obj->date_commande);
467
468
                $this->date_start = $this->db->jdate($obj->date_start);
469
                $this->date_start_real = $this->db->jdate($obj->date_start_real);
470
                $this->date_end = $this->db->jdate($obj->date_end);
471
                $this->date_end_real = $this->db->jdate($obj->date_end_real);
472
                // For backward compatibility
473
                //$this->date_ouverture_prevue = $this->db->jdate($obj->date_ouverture_prevue);
474
                //$this->date_ouverture = $this->db->jdate($obj->date_ouverture);
475
                //$this->date_fin_validite = $this->db->jdate($obj->date_fin_validite);
476
                //$this->date_cloture = $this->db->jdate($obj->date_cloture);
477
478
                $this->tva_tx = $obj->tva_tx;
479
                $this->vat_src_code = $obj->vat_src_code;
480
                $this->localtax1_tx = $obj->localtax1_tx;
481
                $this->localtax2_tx = $obj->localtax2_tx;
482
                $this->localtax1_type = $obj->localtax1_type;
483
                $this->localtax2_type = $obj->localtax2_type;
484
                $this->qty = $obj->qty;
485
                $this->remise_percent = $obj->remise_percent;
486
                $this->fk_remise_except = $obj->fk_remise_except;
487
                $this->subprice = $obj->subprice;
488
                $this->price_ht = $obj->price_ht;
489
                $this->total_ht = $obj->total_ht;
490
                $this->total_tva = $obj->total_tva;
491
                $this->total_localtax1 = $obj->total_localtax1;
492
                $this->total_localtax2 = $obj->total_localtax2;
493
                $this->total_ttc = $obj->total_ttc;
494
                $this->info_bits = $obj->info_bits;
495
                $this->fk_user_author = $obj->fk_user_author;
496
                $this->fk_user_ouverture = $obj->fk_user_ouverture;
497
                $this->fk_user_cloture = $obj->fk_user_cloture;
498
                $this->commentaire = $obj->commentaire;
499
                $this->fk_fournprice = $obj->fk_fournprice;
500
501
                $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->fk_fournprice, $obj->pa_ht);
502
                $this->pa_ht = $marginInfos[0];
503
                $this->fk_unit = $obj->fk_unit;
504
505
                $this->rang = $obj->rang;
506
507
                $this->fetch_optionals();
508
            }
509
510
            $this->db->free($resql);
511
512
            return 1;
513
        } else {
514
            $this->error = "Error " . $this->db->lasterror();
515
            return -1;
516
        }
517
    }
518
519
520
    /**
521
     *      Update database for contract line
522
     *
523
     *      @param  User    $user           User that modify
524
     *      @param  int     $notrigger      0=no, 1=yes (no update trigger)
525
     *      @return int                     Return integer <0 if KO, >0 if OK
526
     */
527
    public function update($user, $notrigger = 0)
528
    {
529
        global $mysoc;
530
531
        $error = 0;
532
533
        // Clean parameters
534
        $this->fk_contrat = (int) $this->fk_contrat;
535
        $this->fk_product = (int) $this->fk_product;
536
        $this->statut = (int) $this->statut;
537
        $this->label = trim($this->label);
538
        $this->description = trim($this->description);
539
        $this->vat_src_code = trim($this->vat_src_code);
540
        $this->tva_tx = trim((string) $this->tva_tx);
541
        $this->localtax1_tx = trim($this->localtax1_tx);
542
        $this->localtax2_tx = trim($this->localtax2_tx);
543
        $this->qty = (float) $this->qty;
544
        $this->remise_percent = trim((string) $this->remise_percent);
545
        $this->fk_remise_except = (int) $this->fk_remise_except;
546
        $this->subprice = (float) price2num($this->subprice);
547
        $this->price_ht = (float) price2num($this->price_ht);
548
        $this->info_bits = (int) $this->info_bits;
549
        $this->fk_user_author = (int) $this->fk_user_author;
550
        $this->fk_user_ouverture = (int) $this->fk_user_ouverture;
551
        $this->fk_user_cloture = (int) $this->fk_user_cloture;
552
        $this->commentaire = trim($this->commentaire);
553
        $this->rang = (int) $this->rang;
554
        //if (empty($this->subprice)) $this->subprice = 0;
555
        if (empty($this->price_ht)) {
556
            $this->price_ht = 0;
557
        }
558
        if (empty($this->total_ht)) {
559
            $this->total_ht = 0;
560
        }
561
        if (empty($this->total_tva)) {
562
            $this->total_tva = 0;
563
        }
564
        if (empty($this->total_ttc)) {
565
            $this->total_ttc = 0;
566
        }
567
        if (empty($this->localtax1_tx)) {
568
            $this->localtax1_tx = 0;
569
        }
570
        if (empty($this->localtax2_tx)) {
571
            $this->localtax2_tx = 0;
572
        }
573
        if (empty($this->remise_percent)) {
574
            $this->remise_percent = 0;
575
        }
576
577
        // Calcul du total TTC et de la TVA pour la ligne a partir de
578
        // qty, pu, remise_percent et txtva
579
        // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
580
        // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
581
        $localtaxes_type = getLocalTaxesFromRate($this->tva_tx, 0, $this->thirdparty, $mysoc);
582
583
        $tabprice = calcul_price_total($this->qty, $this->price_ht, $this->remise_percent, $this->tva_tx, $this->localtax1_tx, $this->localtax2_tx, 0, 'HT', 0, 1, $mysoc, $localtaxes_type);
584
        $this->total_ht  = $tabprice[0];
585
        $this->total_tva = $tabprice[1];
586
        $this->total_ttc = $tabprice[2];
587
        $this->total_localtax1 = $tabprice[9];
588
        $this->total_localtax2 = $tabprice[10];
589
590
        if (empty($this->pa_ht)) {
591
            $this->pa_ht = 0;
592
        }
593
594
        // if buy price not defined, define buyprice as configured in margin admin
595
        if ($this->pa_ht == 0) {
596
            $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
597
            if ($result < 0) {
598
                return -1;
599
            } else {
600
                $this->pa_ht = $result;
601
            }
602
        }
603
604
        // $this->oldcopy should have been set by the caller of update (here properties were already modified)
605
        if (empty($this->oldcopy)) {
606
            dol_syslog("this->oldcopy should have been set by the caller of update (here properties were already modified)", LOG_WARNING);
607
            $this->oldcopy = dol_clone($this, 2);
608
        }
609
610
        $this->db->begin();
611
612
        // Update request
613
        $sql = "UPDATE " . MAIN_DB_PREFIX . "contratdet SET";
614
        $sql .= " fk_contrat = " . ((int) $this->fk_contrat) . ",";
615
        $sql .= " fk_product = " . ($this->fk_product ? ((int) $this->fk_product) : 'null') . ",";
616
        $sql .= " statut = " . ((int) $this->statut) . ",";
617
        $sql .= " label = '" . $this->db->escape($this->label) . "',";
618
        $sql .= " description = '" . $this->db->escape($this->description) . "',";
619
        $sql .= " date_commande = " . ($this->date_commande != '' ? "'" . $this->db->idate($this->date_commande) . "'" : "null") . ",";
620
        $sql .= " date_ouverture_prevue = " . ($this->date_start != '' ? "'" . $this->db->idate($this->date_start) . "'" : "null") . ",";
621
        $sql .= " date_ouverture = " . ($this->date_start_real != '' ? "'" . $this->db->idate($this->date_start_real) . "'" : "null") . ",";
622
        $sql .= " date_fin_validite = " . ($this->date_end != '' ? "'" . $this->db->idate($this->date_end) . "'" : "null") . ",";
623
        $sql .= " date_cloture = " . ($this->date_end_real != '' ? "'" . $this->db->idate($this->date_end_real) . "'" : "null") . ",";
624
        $sql .= " vat_src_code = '" . $this->db->escape($this->vat_src_code) . "',";
625
        $sql .= " tva_tx = " . price2num($this->tva_tx) . ",";
626
        $sql .= " localtax1_tx = " . price2num($this->localtax1_tx) . ",";
627
        $sql .= " localtax2_tx = " . price2num($this->localtax2_tx) . ",";
628
        $sql .= " qty = " . price2num($this->qty) . ",";
629
        $sql .= " remise_percent = " . price2num($this->remise_percent) . ",";
630
        $sql .= " remise = " . ($this->remise ? price2num($this->remise) : "null") . ",";
631
        $sql .= " fk_remise_except = " . ($this->fk_remise_except > 0 ? $this->fk_remise_except : "null") . ",";
632
        $sql .= " subprice = " . ($this->subprice != '' ? $this->subprice : "null") . ",";
633
        $sql .= " price_ht = " . ($this->price_ht != '' ? $this->price_ht : "null") . ",";
634
        $sql .= " total_ht = " . $this->total_ht . ",";
635
        $sql .= " total_tva = " . $this->total_tva . ",";
636
        $sql .= " total_localtax1 = " . $this->total_localtax1 . ",";
637
        $sql .= " total_localtax2 = " . $this->total_localtax2 . ",";
638
        $sql .= " total_ttc = " . $this->total_ttc . ",";
639
        $sql .= " fk_product_fournisseur_price = " . (!empty($this->fk_fournprice) ? $this->fk_fournprice : "NULL") . ",";
640
        $sql .= " buy_price_ht = '" . price2num($this->pa_ht) . "',";
641
        $sql .= " info_bits = '" . $this->db->escape($this->info_bits) . "',";
642
        $sql .= " fk_user_author = " . ($this->fk_user_author >= 0 ? $this->fk_user_author : "NULL") . ",";
643
        $sql .= " fk_user_ouverture = " . ($this->fk_user_ouverture > 0 ? $this->fk_user_ouverture : "NULL") . ",";
644
        $sql .= " fk_user_cloture = " . ($this->fk_user_cloture > 0 ? $this->fk_user_cloture : "NULL") . ",";
645
        $sql .= " commentaire = '" . $this->db->escape($this->commentaire) . "',";
646
        $sql .= " fk_unit = " . (!$this->fk_unit ? 'NULL' : $this->fk_unit) . ",";
647
        $sql .= " rang = " . (empty($this->rang) ? '0' : (int) $this->rang);
648
        $sql .= " WHERE rowid = " . ((int) $this->id);
649
650
        dol_syslog(get_only_class($this) . "::update", LOG_DEBUG);
651
        $resql = $this->db->query($sql);
652
        if (!$resql) {
653
            $this->error = "Error " . $this->db->lasterror();
654
            $error++;
655
        }
656
657
        if (!$error) { // For avoid conflicts if trigger used
658
            $result = $this->insertExtraFields();
659
            if ($result < 0) {
660
                $error++;
661
            }
662
        }
663
664
        // If we change a planned date (start or end) of one contract line, sync dates for all other services too
665
        if (!$error && getDolGlobalString('CONTRACT_SYNC_PLANNED_DATE_OF_SERVICES')) {
666
            dol_syslog(get_only_class($this) . "::update CONTRACT_SYNC_PLANNED_DATE_OF_SERVICES is on so we update date for all lines", LOG_DEBUG);
667
668
            if ($this->date_start != $this->oldcopy->date_start) {
669
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'contratdet SET';
670
                $sql .= " date_ouverture_prevue = " . ($this->date_start != '' ? "'" . $this->db->idate($this->date_start) . "'" : "null");
671
                $sql .= " WHERE fk_contrat = " . ((int) $this->fk_contrat);
672
673
                $resql = $this->db->query($sql);
674
                if (!$resql) {
675
                    $error++;
676
                    $this->error = "Error " . $this->db->lasterror();
677
                }
678
            }
679
            if ($this->date_end != $this->oldcopy->date_end) {
680
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'contratdet SET';
681
                $sql .= " date_fin_validite = " . ($this->date_end != '' ? "'" . $this->db->idate($this->date_end) . "'" : "null");
682
                $sql .= " WHERE fk_contrat = " . ((int) $this->fk_contrat);
683
684
                $resql = $this->db->query($sql);
685
                if (!$resql) {
686
                    $error++;
687
                    $this->error = "Error " . $this->db->lasterror();
688
                }
689
            }
690
        }
691
692
        if (!$error && !$notrigger) {
693
            // Call trigger
694
            $result = $this->call_trigger('LINECONTRACT_MODIFY', $user);
695
            if ($result < 0) {
696
                $error++;
697
                $this->db->rollback();
698
            }
699
            // End call triggers
700
        }
701
702
        if (!$error) {
703
            $this->db->commit();
704
            return 1;
705
        } else {
706
            $this->db->rollback();
707
            $this->errors[] = $this->error;
708
            return -1;
709
        }
710
    }
711
712
713
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
714
    /**
715
     *  Update in database the fields total_xxx of lines
716
     *  Used by migration process
717
     *
718
     *  @return     int     Return integer <0 if KO, >0 if OK
719
     */
720
    public function update_total()
721
    {
722
		// phpcs:enable
723
        $this->db->begin();
724
725
        // Mise a jour ligne en base
726
        $sql = "UPDATE " . MAIN_DB_PREFIX . "contratdet SET";
727
        $sql .= " total_ht=" . price2num($this->total_ht, 'MT');
728
        $sql .= ",total_tva=" . price2num($this->total_tva, 'MT');
729
        $sql .= ",total_localtax1=" . price2num($this->total_localtax1, 'MT');
730
        $sql .= ",total_localtax2=" . price2num($this->total_localtax2, 'MT');
731
        $sql .= ",total_ttc=" . price2num($this->total_ttc, 'MT');
732
        $sql .= " WHERE rowid = " . ((int) $this->id);
733
734
        dol_syslog(get_only_class($this) . "::update_total", LOG_DEBUG);
735
736
        $resql = $this->db->query($sql);
737
        if ($resql) {
738
            $this->db->commit();
739
            return 1;
740
        } else {
741
            $this->error = $this->db->error();
742
            $this->db->rollback();
743
            return -2;
744
        }
745
    }
746
747
748
    /**
749
     * Inserts a contrat line into database
750
     *
751
     * @param int $notrigger Set to 1 if you don't want triggers to be fired
752
     * @return int Return integer <0 if KO, >0 if OK
753
     */
754
    public function insert($notrigger = 0)
755
    {
756
        global $user;
757
758
        $error = 0;
759
760
        // Insertion dans la base
761
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "contratdet";
762
        $sql .= " (fk_contrat, label, description, fk_product, qty, vat_src_code, tva_tx,";
763
        $sql .= " localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, remise_percent, subprice,";
764
        $sql .= " total_ht, total_tva, total_localtax1, total_localtax2, total_ttc,";
765
        $sql .= " info_bits,";
766
        $sql .= " rang,";
767
        $sql .= " price_ht, remise, fk_product_fournisseur_price, buy_price_ht";
768
        if ($this->date_start > 0) {
769
            $sql .= ",date_ouverture_prevue";
770
        }
771
        if ($this->date_end > 0) {
772
            $sql .= ",date_fin_validite";
773
        }
774
        $sql .= ") VALUES ($this->fk_contrat, '', '" . $this->db->escape($this->description) . "',";
775
        $sql .= ($this->fk_product > 0 ? $this->fk_product : "null") . ",";
776
        $sql .= " '" . $this->db->escape($this->qty) . "',";
777
        $sql .= " '" . $this->db->escape($this->vat_src_code) . "',";
778
        $sql .= " '" . $this->db->escape($this->tva_tx) . "',";
779
        $sql .= " '" . $this->db->escape($this->localtax1_tx) . "',";
780
        $sql .= " '" . $this->db->escape($this->localtax2_tx) . "',";
781
        $sql .= " '" . $this->db->escape($this->localtax1_type) . "',";
782
        $sql .= " '" . $this->db->escape($this->localtax2_type) . "',";
783
        $sql .= " " . price2num($this->remise_percent) . "," . price2num($this->subprice) . ",";
784
        $sql .= " " . price2num($this->total_ht) . "," . price2num($this->total_tva) . "," . price2num($this->total_localtax1) . "," . price2num($this->total_localtax2) . "," . price2num($this->total_ttc) . ",";
785
        $sql .= " '" . $this->db->escape($this->info_bits) . "',";
786
        $sql .= " " . (empty($this->rang) ? '0' : (int) $this->rang) . ",";
787
        $sql .= " " . price2num($this->price_ht) . "," . price2num($this->remise) . ",";
788
        if ($this->fk_fournprice > 0) {
789
            $sql .= ' ' . ((int) $this->fk_fournprice) . ',';
790
        } else {
791
            $sql .= ' null,';
792
        }
793
        if ($this->pa_ht > 0) {
794
            $sql .= ' ' . ((float) price2num($this->pa_ht));
795
        } else {
796
            $sql .= ' null';
797
        }
798
        if ($this->date_start > 0) {
799
            $sql .= ",'" . $this->db->idate($this->date_start) . "'";
800
        }
801
        if ($this->date_end > 0) {
802
            $sql .= ",'" . $this->db->idate($this->date_end) . "'";
803
        }
804
        $sql .= ")";
805
806
        dol_syslog(get_only_class($this) . "::insert", LOG_DEBUG);
807
808
        $resql = $this->db->query($sql);
809
        if ($resql) {
810
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . 'contratdet');
811
812
            // Insert of extrafields
813
            if (!$error) {
814
                $result = $this->insertExtraFields();
815
                if ($result < 0) {
816
                    $this->db->rollback();
817
                    return -1;
818
                }
819
            }
820
821
            if (!$notrigger) {
822
                // Call trigger
823
                $result = $this->call_trigger('LINECONTRACT_INSERT', $user);
824
                if ($result < 0) {
825
                    $this->db->rollback();
826
                    return -1;
827
                }
828
                // End call triggers
829
            }
830
831
            $this->db->commit();
832
            return 1;
833
        } else {
834
            $this->db->rollback();
835
            $this->error = $this->db->error() . " sql=" . $sql;
836
            return -1;
837
        }
838
    }
839
840
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
841
    /**
842
     *  Activate a contract line
843
     *
844
     * @param   User        $user       Object User who activate contract
845
     * @param   int         $date       Date real activation
846
     * @param   int|string  $date_end   Date planned end. Use '-1' to keep it unchanged.
847
     * @param   string      $comment    A comment typed by user
848
     * @return  int                     Return integer <0 if KO, >0 if OK
849
     */
850
    public function active_line($user, $date, $date_end = '', $comment = '')
851
    {
852
		// phpcs:enable
853
        $error = 0;
854
855
        $this->db->begin();
856
857
        $this->statut = ContratLigne::STATUS_OPEN;
858
        $this->date_start_real = $date;
859
        $this->date_end = $date_end;
860
        $this->fk_user_ouverture = $user->id;
861
        $this->date_end_real = null;
862
        $this->commentaire = $comment;
863
864
        $sql = "UPDATE " . MAIN_DB_PREFIX . "contratdet SET statut = " . ((int) $this->statut) . ",";
865
        $sql .= " date_ouverture = " . (dol_strlen($this->date_start_real) != 0 ? "'" . $this->db->idate($this->date_start_real) . "'" : "null") . ",";
866
        if ($date_end >= 0) {
867
            $sql .= " date_fin_validite = " . (dol_strlen($this->date_end) != 0 ? "'" . $this->db->idate($this->date_end) . "'" : "null") . ",";
868
        }
869
        $sql .= " fk_user_ouverture = " . ((int) $this->fk_user_ouverture) . ",";
870
        $sql .= " date_cloture = null,";
871
        $sql .= " commentaire = '" . $this->db->escape($comment) . "'";
872
        $sql .= " WHERE rowid = " . ((int) $this->id) . " AND (statut = " . ContratLigne::STATUS_INITIAL . " OR statut = " . ContratLigne::STATUS_CLOSED . ")";
873
874
        dol_syslog(get_only_class($this) . "::active_line", LOG_DEBUG);
875
        $resql = $this->db->query($sql);
876
        if ($resql) {
877
            // Call trigger
878
            $result = $this->call_trigger('LINECONTRACT_ACTIVATE', $user);
879
            if ($result < 0) {
880
                $error++;
881
            }
882
            // End call triggers
883
884
            if (!$error) {
885
                $this->db->commit();
886
                return 1;
887
            } else {
888
                $this->db->rollback();
889
                return -1;
890
            }
891
        } else {
892
            $this->error = $this->db->lasterror();
893
            $this->db->rollback();
894
            return -1;
895
        }
896
    }
897
898
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
899
    /**
900
     *  Close a contract line
901
     *
902
     * @param    User   $user           Object User who close contract
903
     * @param    int    $date_end_real  Date end
904
     * @param    string $comment        A comment typed by user
905
     * @param    int    $notrigger      1=Does not execute triggers, 0=Execute triggers
906
     * @return int                      Return integer <0 if KO, >0 if OK
907
     */
908
    public function close_line($user, $date_end_real, $comment = '', $notrigger = 0)
909
    {
910
		// phpcs:enable
911
        $this->date_cloture = $date_end_real;
912
        $this->date_end_real = $date_end_real;
913
        $this->user_closing_id = $user->id;
914
        $this->commentaire = $comment;
915
916
        $error = 0;
917
918
        // statut actif : 4
919
920
        $this->db->begin();
921
922
        $sql = "UPDATE " . MAIN_DB_PREFIX . "contratdet SET statut = " . ((int) ContratLigne::STATUS_CLOSED) . ",";
923
        $sql .= " date_cloture = '" . $this->db->idate($date_end_real) . "',";
924
        $sql .= " fk_user_cloture = " . ((int) $user->id) . ",";
925
        $sql .= " commentaire = '" . $this->db->escape($comment) . "'";
926
        $sql .= " WHERE rowid = " . ((int) $this->id) . " AND statut = " . ((int) ContratLigne::STATUS_OPEN);
927
928
        $resql = $this->db->query($sql);
929
        if ($resql) {
930
            if (!$notrigger) {
931
                // Call trigger
932
                $result = $this->call_trigger('LINECONTRACT_CLOSE', $user);
933
                if ($result < 0) {
934
                    $error++;
935
                    $this->db->rollback();
936
                    return -1;
937
                }
938
                // End call triggers
939
            }
940
941
            $this->db->commit();
942
            return 1;
943
        } else {
944
            $this->error = $this->db->lasterror();
945
            $this->db->rollback();
946
            return -1;
947
        }
948
    }
949
}
950