Test Failed
Branch main (a69845)
by Rafael
63:42
created

FactureRec::addline()   F

Complexity

Conditions 23
Paths > 20000

Size

Total Lines 174
Code Lines 135

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 135
c 0
b 0
f 0
nc 262145
nop 23
dl 0
loc 174
rs 0

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* Copyright (C) 2003-2005  Rodolphe Quiedeville    <[email protected]>
4
 * Copyright (C) 2004-2019	Laurent Destailleur		<[email protected]>
5
 * Copyright (C) 2009-2012	Regis Houssin			<[email protected]>
6
 * Copyright (C) 2010-2011	Juanjo Menent			<[email protected]>
7
 * Copyright (C) 2012       Cedric Salvador         <[email protected]>
8
 * Copyright (C) 2013       Florian Henry		  	<[email protected]>
9
 * Copyright (C) 2015       Marcos García           <[email protected]>
10
 * Copyright (C) 2017-2024  Frédéric France         <[email protected]>
11
 * Copyright (C) 2023       Nick Fragoulis
12
 * Copyright (C) 2024		MDW							<[email protected]>
13
 * Copyright (C) 2024       Rafael San José             <[email protected]>
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 3 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27
 */
28
29
/**
30
 *  \file       htdocs/compta/facture/class/facture-rec.class.php
31
 *  \ingroup    invoice
32
 *  \brief      File of class to manage recurring invoices
33
 */
34
35
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/commoninvoice.class.php';
36
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/notify.class.php';
37
require_once constant('DOL_DOCUMENT_ROOT') . '/product/class/product.class.php';
38
require_once constant('DOL_DOCUMENT_ROOT') . '/compta/facture/class/facture.class.php';
39
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/date.lib.php';
40
41
42
/**
43
 *  Class to manage invoice templates
44
 */
45
class FactureRec extends CommonInvoice
46
{
47
    const TRIGGER_PREFIX = 'BILLREC';
48
    /**
49
     * @var string ID to identify managed object
50
     */
51
    public $element = 'facturerec';
52
53
    /**
54
     * @var string Name of table without prefix where object is stored
55
     */
56
    public $table_element = 'facture_rec';
57
58
    /**
59
     * @var string    Name of subtable line
60
     */
61
    public $table_element_line = 'facturedet_rec';
62
63
    /**
64
     * @var string Field with ID of parent key if this field has a parent
65
     */
66
    public $fk_element = 'fk_facture';
67
68
    /**
69
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
70
     */
71
    public $picto = 'bill';
72
73
    /**
74
     * @var int Entity
75
     */
76
    public $entity;
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    protected $table_ref_field = 'titre';
82
83
    /**
84
     * @var string The label of recurring invoice
85
     */
86
    public $title;
87
88
    /**
89
     * @var string  The label of recurring invoice
90
     * @deprecated  Use $title instead
91
     */
92
    public $titre;
93
94
    /**
95
     * @var double
96
     */
97
    public $multicurrency_subprice;
98
    public $socid;
99
    public $number;
100
    public $date;
101
    //public $remise;
102
    //public $remise_absolue;
103
    //public $remise_percent;
104
105
    /**
106
     * @deprecated
107
     * @see $total_ht
108
     */
109
    public $total;
110
111
    /**
112
     * @deprecated
113
     * @see $total_tva
114
     */
115
    public $tva;
116
117
    public $date_last_gen;
118
    public $date_when;
119
    public $nb_gen_done;
120
    public $nb_gen_max;
121
122
    public $user_author;
123
124
    /**
125
     * @var int Frequency
126
     */
127
    public $frequency;
128
129
    /**
130
     * @var string Unit frequency
131
     */
132
    public $unit_frequency;
133
134
    public $rang;
135
136
    /**
137
     * @var int special code
138
     */
139
    public $special_code;
140
141
    public $usenewprice = 0;
142
143
    /**
144
     * @var int Deadline for payment
145
     */
146
    public $date_lim_reglement;
147
    public $cond_reglement_code; // Code in llx_c_paiement
148
    public $mode_reglement_code; // Code in llx_c_paiement
149
150
    public $suspended; // status
151
152
    public $auto_validate; // 0 to create in draft, 1 to create and validate the new invoice
153
    public $generate_pdf; // 1 to generate PDF on invoice generation (default)
154
155
156
    /**
157
     *  'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
158
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
159
     *  'label' the translation key.
160
     *  'enabled' is a condition when the field must be managed.
161
     *  'position' is the sort order of field.
162
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
163
     *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
164
     *  'noteditable' says if field is not editable (1 or 0)
165
     *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
166
     *  'index' if we want an index in database.
167
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
168
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
169
     *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
170
     *  'css' is the CSS style to use on field. For example: 'maxwidth200'
171
     *  'help' is a string visible as a tooltip on field
172
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
173
     *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
174
     *  'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
175
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
176
     *
177
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
178
     */
179
180
    // BEGIN MODULEBUILDER PROPERTIES
181
    /**
182
     * @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...
183
     */
184
    public $fields = array(
185
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
186
        'titre' => array('type' => 'varchar(100)', 'label' => 'Titre', 'enabled' => 1, 'showoncombobox' => 1, 'visible' => -1, 'position' => 15),
187
        'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 20, 'index' => 1),
188
        'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 25),
189
        'subtype' => array('type' => 'smallint(6)', 'label' => 'InvoiceSubtype', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 30),
190
        'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 35),
191
        'total_tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 55, 'isameasure' => 1),
192
        'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 60, 'isameasure' => 1),
193
        'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 65, 'isameasure' => 1),
194
        'total_ht' => array('type' => 'double(24,8)', 'label' => 'Total', 'enabled' => 1, 'visible' => -1, 'position' => 70, 'isameasure' => 1),
195
        'total_ttc' => array('type' => 'double(24,8)', 'label' => 'Total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 75, 'isameasure' => 1),
196
        'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fk user author', 'enabled' => 1, 'visible' => -1, 'position' => 80),
197
        'fk_projet' => array('type' => 'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label' => 'Fk projet', 'enabled' => "isModEnabled('project')", 'visible' => -1, 'position' => 85),
198
        'fk_cond_reglement' => array('type' => 'integer', 'label' => 'Fk cond reglement', 'enabled' => 1, 'visible' => -1, 'position' => 90),
199
        'fk_mode_reglement' => array('type' => 'integer', 'label' => 'Fk mode reglement', 'enabled' => 1, 'visible' => -1, 'position' => 95),
200
        'date_lim_reglement' => array('type' => 'date', 'label' => 'Date lim reglement', 'enabled' => 1, 'visible' => -1, 'position' => 100),
201
        'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 105),
202
        'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 110),
203
        'modelpdf' => array('type' => 'varchar(255)', 'label' => 'Modelpdf', 'enabled' => 1, 'visible' => -1, 'position' => 115),
204
        'date_when' => array('type' => 'datetime', 'label' => 'Date when', 'enabled' => 1, 'visible' => -1, 'position' => 130),
205
        'date_last_gen' => array('type' => 'datetime', 'label' => 'Date last gen', 'enabled' => 1, 'visible' => -1, 'position' => 135),
206
        'nb_gen_done' => array('type' => 'integer', 'label' => 'Nb gen done', 'enabled' => 1, 'visible' => -1, 'position' => 140),
207
        'nb_gen_max' => array('type' => 'integer', 'label' => 'Nb gen max', 'enabled' => 1, 'visible' => -1, 'position' => 145),
208
        'frequency' => array('type' => 'integer', 'label' => 'Frequency', 'enabled' => 1, 'visible' => -1, 'position' => 150),
209
        'unit_frequency' => array('type' => 'varchar(2)', 'label' => 'UnitFrequency', 'enabled' => 1, 'visible' => -1, 'position' => 152),
210
        'usenewprice' => array('type' => 'integer', 'label' => 'UseNewPrice', 'enabled' => 1, 'visible' => 0, 'position' => 155),
211
        'revenuestamp' => array('type' => 'double(24,8)', 'label' => 'RevenueStamp', 'enabled' => 1, 'visible' => -1, 'position' => 160, 'isameasure' => 1),
212
        'auto_validate' => array('type' => 'integer', 'label' => 'Auto validate', 'enabled' => 1, 'visible' => -1, 'position' => 165),
213
        'generate_pdf' => array('type' => 'integer', 'label' => 'Generate pdf', 'enabled' => 1, 'visible' => -1, 'position' => 170),
214
        'fk_account' => array('type' => 'integer', 'label' => 'Fk account', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 175),
215
        'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 1, 'visible' => -1, 'position' => 180),
216
        'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrency code', 'enabled' => 1, 'visible' => -1, 'position' => 185),
217
        'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrency tx', 'enabled' => 1, 'visible' => -1, 'position' => 190, 'isameasure' => 1),
218
        'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ht', 'enabled' => 1, 'visible' => -1, 'position' => 195, 'isameasure' => 1),
219
        'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total tva', 'enabled' => 1, 'visible' => -1, 'position' => 200, 'isameasure' => 1),
220
        'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 205, 'isameasure' => 1),
221
        'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 210),
222
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 215),
223
        'suspended' => array('type' => 'integer', 'label' => 'Suspended', 'enabled' => 1, 'visible' => -1, 'position' => 225),
224
    );
225
    // END MODULEBUILDER PROPERTIES
226
227
    const STATUS_NOTSUSPENDED = 0;
228
    const STATUS_SUSPENDED = 1;
229
230
231
232
    /**
233
     *  Constructor
234
     *
235
     *  @param      DoliDB      $db     Database handler
236
     */
237
    public function __construct(DoliDB $db)
238
    {
239
        $this->db = $db;
240
    }
241
242
    /**
243
     *  Create a predefined invoice
244
     *
245
     *  @param      User    $user       User object
246
     *  @param      int     $facid      Id of source invoice
247
     *  @param      int     $notrigger  No trigger
248
     *  @param      array   $onlylines  Only the lines of the array
249
     *  @return     int                 Return integer <0 if KO, id of invoice created if OK
250
     */
251
    public function create($user, $facid, $notrigger = 0, $onlylines = array())
252
    {
253
        global $conf;
254
255
        $error = 0;
256
        $now = dol_now();
257
258
        // Clean parameters
259
        $this->titre = trim(isset($this->titre) ? $this->titre : $this->title); // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property FactureRec::$titre has been deprecated: Use $title instead ( Ignorable by Annotation )

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

259
        /** @scrutinizer ignore-deprecated */ $this->titre = trim(isset($this->titre) ? $this->titre : $this->title); // deprecated

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...
260
        $this->title = trim($this->title);
261
        $this->usenewprice = empty($this->usenewprice) ? 0 : $this->usenewprice;
262
        if (empty($this->suspended)) {
263
            $this->suspended = 0;
264
        }
265
266
        // No frequency defined then no next date to execution
267
        if (empty($this->frequency)) {
268
            $this->frequency = 0;
269
            $this->date_when = null;
270
        }
271
272
        $this->frequency = abs($this->frequency);
273
        $this->nb_gen_done = 0;
274
        $this->nb_gen_max = empty($this->nb_gen_max) ? 0 : $this->nb_gen_max;
275
        $this->auto_validate = empty($this->auto_validate) ? 0 : $this->auto_validate;
276
        $this->generate_pdf = empty($this->generate_pdf) ? 0 : $this->generate_pdf;
277
278
        $this->db->begin();
279
280
        // Load invoice template
281
        $facsrc = new Facture($this->db);
282
        $result = $facsrc->fetch($facid);
283
        if ($result > 0) {
284
            $this->socid = $facsrc->socid;
285
286
            $sql = "INSERT INTO " . MAIN_DB_PREFIX . "facture_rec (";
287
            $sql .= "titre";
288
            $sql .= ", fk_soc";
289
            $sql .= ", subtype";
290
            $sql .= ", entity";
291
            $sql .= ", datec";
292
            $sql .= ", amount";
293
            //$sql .= ", remise";
294
            $sql .= ", note_private";
295
            $sql .= ", note_public";
296
            $sql .= ", modelpdf";
297
            $sql .= ", fk_user_author";
298
            $sql .= ", fk_projet";
299
            $sql .= ", fk_account";
300
            $sql .= ", fk_cond_reglement";
301
            $sql .= ", fk_mode_reglement";
302
            $sql .= ", usenewprice";
303
            $sql .= ", frequency";
304
            $sql .= ", unit_frequency";
305
            $sql .= ", date_when";
306
            $sql .= ", date_last_gen";
307
            $sql .= ", nb_gen_done";
308
            $sql .= ", nb_gen_max";
309
            $sql .= ", auto_validate";
310
            $sql .= ", generate_pdf";
311
            $sql .= ", fk_multicurrency";
312
            $sql .= ", multicurrency_code";
313
            $sql .= ", multicurrency_tx";
314
            $sql .= ", suspended";
315
            $sql .= ") VALUES (";
316
            $sql .= "'" . $this->db->escape($this->titre ? $this->titre : $this->title) . "'";
0 ignored issues
show
Deprecated Code introduced by
The property FactureRec::$titre has been deprecated: Use $title instead ( Ignorable by Annotation )

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

316
            $sql .= "'" . $this->db->escape($this->titre ? /** @scrutinizer ignore-deprecated */ $this->titre : $this->title) . "'";

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...
317
            $sql .= ", " . ((int) $this->socid);
318
            $sql .= ", " . ($this->subtype ? "'" . $this->db->escape($this->subtype) . "'" : "null");
319
            $sql .= ", " . ((int) $conf->entity);
320
            $sql .= ", '" . $this->db->idate($now) . "'";
321
            $sql .= ", " . (!empty($facsrc->total_ttc) ? ((float) $facsrc->total_ttc) : '0');
322
            //$sql .= ", ".(!empty($facsrc->remise_absolue) ? ((float) $this->remise_absolue) : '0');
323
            $sql .= ", " . (!empty($this->note_private) ? ("'" . $this->db->escape($this->note_private) . "'") : "NULL");
324
            $sql .= ", " . (!empty($this->note_public) ? ("'" . $this->db->escape($this->note_public) . "'") : "NULL");
325
            $sql .= ", " . (!empty($this->model_pdf) ? ("'" . $this->db->escape($this->model_pdf) . "'") : "NULL");
326
            $sql .= ", " . ((int) $user->id);
327
            $sql .= ", " . (!empty($this->fk_project) ? ((int) $this->fk_project) : "null");
328
            $sql .= ", " . (!empty($facsrc->fk_account) ? ((int) $facsrc->fk_account) : "null");
329
            $sql .= ", " . ($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
330
            $sql .= ", " . ($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
331
            $sql .= ", " . ((int) $this->usenewprice);
332
            $sql .= ", " . ((int) $this->frequency);
333
            $sql .= ", '" . $this->db->escape($this->unit_frequency) . "'";
334
            $sql .= ", " . (!empty($this->date_when) ? "'" . $this->db->idate($this->date_when) . "'" : 'NULL');
335
            $sql .= ", " . (!empty($this->date_last_gen) ? "'" . $this->db->idate($this->date_last_gen) . "'" : 'NULL');
336
            $sql .= ", " . ((int) $this->nb_gen_done);
337
            $sql .= ", " . ((int) $this->nb_gen_max);
338
            $sql .= ", " . ((int) $this->auto_validate);
339
            $sql .= ", " . ((int) $this->generate_pdf);
340
            $sql .= ", " . ((int) $facsrc->fk_multicurrency);
341
            $sql .= ", '" . $this->db->escape($facsrc->multicurrency_code) . "'";
342
            $sql .= ", " . ((float) $facsrc->multicurrency_tx);
343
            $sql .= ", " . ((int) $this->suspended);
344
            $sql .= ")";
345
346
            if ($this->db->query($sql)) {
347
                $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "facture_rec");
348
349
                // Fields used into addline later
350
                $this->fk_multicurrency = $facsrc->fk_multicurrency;
351
                $this->multicurrency_code = $facsrc->multicurrency_code;
352
                $this->multicurrency_tx = $facsrc->multicurrency_tx;
353
354
                // Add lines
355
                $fk_parent_line = 0;
356
357
                $num = count($facsrc->lines);
358
                for ($i = 0; $i < $num; $i++) {
359
                    if (!empty($onlylines) && !in_array($facsrc->lines[$i]->id, $onlylines)) {
360
                        continue; // Skip unselected lines
361
                    }
362
363
                    // Reset fk_parent_line for no child products and special product
364
                    if (($facsrc->lines[$i]->product_type != 9 && empty($facsrc->lines[$i]->fk_parent_line)) || $facsrc->lines[$i]->product_type == 9) {
0 ignored issues
show
Bug Best Practice introduced by
The property fk_parent_line does not exist on CommonInvoiceLine. Since you implemented __get, consider adding a @property annotation.
Loading history...
365
                        $fk_parent_line = 0;
366
                    }
367
368
                    $tva_tx = $facsrc->lines[$i]->tva_tx;
369
                    if (!empty($facsrc->lines[$i]->vat_src_code) && !preg_match('/\(/', (string) $tva_tx)) {
370
                        $tva_tx .= ' (' . $facsrc->lines[$i]->vat_src_code . ')';
371
                    }
372
373
                    $default_start_fill = getDolGlobalInt('INVOICEREC_SET_AUTOFILL_DATE_START');
374
                    $default_end_fill = getDolGlobalInt('INVOICEREC_SET_AUTOFILL_DATE_END');
375
376
                    $result_insert = $this->addline(
377
                        $facsrc->lines[$i]->desc,
378
                        $facsrc->lines[$i]->subprice,
379
                        $facsrc->lines[$i]->qty,
380
                        $tva_tx,
381
                        $facsrc->lines[$i]->localtax1_tx,
382
                        $facsrc->lines[$i]->localtax2_tx,
383
                        $facsrc->lines[$i]->fk_product,
384
                        $facsrc->lines[$i]->remise_percent,
385
                        'HT',
386
                        $facsrc->lines[$i]->info_bits,
387
                        '',
388
                        0,
389
                        $facsrc->lines[$i]->product_type,
390
                        $facsrc->lines[$i]->rang,
0 ignored issues
show
Bug Best Practice introduced by
The property rang does not exist on CommonInvoiceLine. Since you implemented __get, consider adding a @property annotation.
Loading history...
391
                        $facsrc->lines[$i]->special_code,
392
                        $facsrc->lines[$i]->label,
393
                        $facsrc->lines[$i]->fk_unit,
394
                        $facsrc->lines[$i]->multicurrency_subprice,
395
                        $default_start_fill,
396
                        $default_end_fill,
397
                        null,
398
                        $facsrc->lines[$i]->pa_ht,
399
                        $fk_parent_line
400
                    );
401
402
                    // Defined the new fk_parent_line
403
                    if ($result_insert > 0 && $facsrc->lines[$i]->product_type == 9) {
404
                        $fk_parent_line = $result_insert;
405
                    }
406
407
                    if ($result_insert < 0) {
408
                        $error++;
409
                    } else {
410
                        $objectline = new FactureLigneRec($this->db);
411
412
                        $result2 = $objectline->fetch($result_insert);
413
                        if ($result2 > 0) {
414
                            // Extrafields
415
                            if (method_exists($facsrc->lines[$i], 'fetch_optionals')) {
416
                                $facsrc->lines[$i]->fetch_optionals($facsrc->lines[$i]->id);
417
                                $objectline->array_options = $facsrc->lines[$i]->array_options;
418
                            }
419
420
                            $result = $objectline->insertExtraFields();
421
                            if ($result < 0) {
422
                                $error++;
423
                            }
424
                        } elseif ($result2 < 0) {
425
                            $this->errors[] = $objectline->error;
426
                            $error++;
427
                        }
428
                    }
429
                }
430
431
                if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) {  // To use new linkedObjectsIds instead of old linked_objects
432
                    $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
433
                }
434
435
                // Add object linked
436
                if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
437
                    foreach ($this->linked_objects as $origin => $tmp_origin_id) {
438
                        if (is_array($tmp_origin_id)) {       // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...))
439
                            foreach ($tmp_origin_id as $origin_id) {
440
                                $ret = $this->add_object_linked($origin, $origin_id);
441
                                if (!$ret) {
442
                                    $this->error = $this->db->lasterror();
443
                                    $error++;
444
                                }
445
                            }
446
                        } else { // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
447
                            $origin_id = $tmp_origin_id;
448
                            $ret = $this->add_object_linked($origin, $origin_id);
449
                            if (!$ret) {
450
                                $this->error = $this->db->lasterror();
451
                                $error++;
452
                            }
453
                        }
454
                    }
455
                }
456
457
                if (!$error) {
458
                    $result = $this->insertExtraFields();
459
                    if ($result < 0) {
460
                        $error++;
461
                    }
462
                }
463
464
                if (!$error && !$notrigger) {
465
                    // Call trigger
466
                    $result = $this->call_trigger('BILLREC_CREATE', $user);
467
                    if ($result < 0) {
468
                        $this->db->rollback();
469
                        return -2;
470
                    }
471
                    // End call triggers
472
                }
473
474
                if ($error) {
475
                    $this->db->rollback();
476
                    return -3;
477
                } else {
478
                    $this->db->commit();
479
                    return $this->id;
480
                }
481
            } else {
482
                $this->error = $this->db->lasterror();
483
                $this->db->rollback();
484
                return -2;
485
            }
486
        } else {
487
            $this->db->rollback();
488
            return -1;
489
        }
490
    }
491
492
493
    /**
494
     *  Update a line invoice_rec.
495
     *
496
     *  @param      User    $user                   User
497
     *  @param      int     $notrigger              No trigger
498
     *  @return     int                             Return integer <0 if KO, Id of line if OK
499
     */
500
    public function update(User $user, $notrigger = 0)
501
    {
502
        $error = 0;
503
504
        $sql = "UPDATE " . MAIN_DB_PREFIX . "facture_rec SET";
505
        $sql .= " entity = " . ((int) $this->entity) . ",";
506
        $sql .= " titre = '" . $this->db->escape($this->title) . "',";
507
        $sql .= " suspended = " . ((int) $this->suspended) . ",";
508
        $sql .= " fk_soc = " . ((int) $this->socid) . ",";
509
        $sql .= " total_tva = " . ((float) $this->total_tva) . ",";
510
        $sql .= " localtax1 = " . ((float) $this->total_localtax1) . ",";
511
        $sql .= " localtax2 = " . ((float) $this->total_localtax2) . ",";
512
        $sql .= " total_ht = " . ((float) $this->total_ht) . ",";
513
        $sql .= " total_ttc = " . ((float) $this->total_ttc);
514
        // TODO Add missing fields
515
        $sql .= " WHERE rowid = " . ((int) $this->id);
516
517
        $this->db->begin();
518
519
        dol_syslog(get_class($this) . "::update", LOG_DEBUG);
520
521
        $resql = $this->db->query($sql);
522
        if ($resql) {
523
            if (!$error) {
524
                $result = $this->insertExtraFields();
525
                if ($result < 0) {
526
                    $error++;
527
                }
528
            }
529
530
            if (!$error && !$notrigger) {
531
                // Call trigger
532
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
533
                if ($result < 0) {
534
                    $this->db->rollback();
535
                    return -2;
536
                }
537
                // End call triggers
538
            }
539
            $this->db->commit();
540
            return 1;
541
        } else {
542
            $this->error = $this->db->lasterror();
543
            $this->db->rollback();
544
            return -1;
545
        }
546
    }
547
548
    /**
549
     *  Load object and lines
550
     *
551
     *  @param      int     $rowid          Id of object to load
552
     *  @param      string  $ref            Reference of recurring invoice
553
     *  @param      string  $ref_ext        External reference of invoice
554
     *  @param      int     $noextrafields  0=Default to load extrafields, 1=No extrafields
555
     *  @param      int     $nolines        0=Default to load lines, 1=No lines
556
     *  @return     int                     >0 if OK, <0 if KO, 0 if not found
557
     */
558
    public function fetch($rowid, $ref = '', $ref_ext = '', $noextrafields = 0, $nolines = 0)
559
    {
560
        dol_syslog('FactureRec::fetch', LOG_DEBUG);
561
562
        $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc, f.subtype, f.total_tva, f.localtax1, f.localtax2, f.total_ht, f.total_ttc';
563
        $sql .= ', f.date_lim_reglement as dlr';
564
        $sql .= ', f.note_private, f.note_public, f.fk_user_author';
565
        $sql .= ', f.modelpdf as model_pdf';
566
        $sql .= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet as fk_project';
567
        $sql .= ', f.fk_account';
568
        $sql .= ', f.frequency, f.unit_frequency, f.date_when, f.date_last_gen, f.nb_gen_done, f.nb_gen_max, f.usenewprice, f.auto_validate';
569
        $sql .= ', f.generate_pdf';
570
        $sql .= ", f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc";
571
        $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
572
        $sql .= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc';
573
        //$sql.= ', el.fk_source';
574
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
575
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_payment_term as c ON f.fk_cond_reglement = c.rowid';
576
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as p ON f.fk_mode_reglement = p.id';
577
        //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'";
578
        $sql .= ' WHERE f.entity IN (' . getEntity('invoice') . ')';
579
        if ($rowid) {
580
            $sql .= ' AND f.rowid = ' . ((int) $rowid);
581
        } elseif ($ref) {
582
            $sql .= " AND f.titre = '" . $this->db->escape($ref) . "'";
583
        } else {
584
            $sql .= ' AND f.rowid = 0';
585
        }
586
        /* This field are not used for template invoice
587
         if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'";
588
         */
589
590
        $result = $this->db->query($sql);
591
        if ($result) {
592
            if ($this->db->num_rows($result)) {
593
                $obj = $this->db->fetch_object($result);
594
595
                $this->id                     = $obj->rowid;
596
                $this->entity                 = $obj->entity;
597
                $this->titre                  = $obj->title; // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property FactureRec::$titre has been deprecated: Use $title instead ( Ignorable by Annotation )

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

597
                /** @scrutinizer ignore-deprecated */ $this->titre                  = $obj->title; // deprecated

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...
598
                $this->title                  = $obj->title;
599
                $this->ref                    = $obj->title;
600
                $this->subtype                = $obj->subtype;
601
                $this->suspended              = $obj->suspended;
602
                $this->total_ht               = $obj->total_ht;
603
                $this->total_tva              = $obj->total_tva;
604
                $this->total_localtax1        = $obj->localtax1;
605
                $this->total_localtax2        = $obj->localtax2;
606
                $this->total_ttc              = $obj->total_ttc;
607
                $this->socid                  = $obj->fk_soc;
608
                $this->date_lim_reglement     = $this->db->jdate($obj->dlr);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->jdate($obj->dlr) can also be of type string. However, the property $date_lim_reglement 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...
609
                $this->mode_reglement_id      = $obj->fk_mode_reglement;
610
                $this->mode_reglement_code    = $obj->mode_reglement_code;
611
                $this->mode_reglement         = $obj->mode_reglement_libelle;
612
                $this->cond_reglement_id      = $obj->fk_cond_reglement;
613
                $this->cond_reglement_code    = $obj->cond_reglement_code;
614
                $this->cond_reglement         = $obj->cond_reglement_libelle;
0 ignored issues
show
Bug Best Practice introduced by
The property $cond_reglement is declared private in CommonObject. Since you implement __set, consider adding a @property or @property-write.
Loading history...
Deprecated Code introduced by
The property CommonObject::$cond_reglement has been deprecated: Use $cond_reglement_id instead - Kept for compatibility ( Ignorable by Annotation )

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

614
                /** @scrutinizer ignore-deprecated */ $this->cond_reglement         = $obj->cond_reglement_libelle;

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...
615
                $this->cond_reglement_doc     = $obj->cond_reglement_libelle_doc;
616
                $this->fk_project             = $obj->fk_project;
617
                $this->fk_account             = $obj->fk_account;
618
                $this->note_private           = $obj->note_private;
619
                $this->note_public            = $obj->note_public;
620
                $this->user_author            = $obj->fk_user_author;
621
                $this->model_pdf              = $obj->model_pdf;
622
                //$this->special_code = $obj->special_code;
623
                $this->frequency              = $obj->frequency;
624
                $this->unit_frequency = $obj->unit_frequency;
625
                $this->date_when              = $this->db->jdate($obj->date_when);
626
                $this->date_last_gen = $this->db->jdate($obj->date_last_gen);
627
                $this->nb_gen_done            = $obj->nb_gen_done;
628
                $this->nb_gen_max = $obj->nb_gen_max;
629
                $this->usenewprice            = $obj->usenewprice;
630
                $this->auto_validate = $obj->auto_validate;
631
                $this->generate_pdf = $obj->generate_pdf;
632
633
                // Multicurrency
634
                $this->fk_multicurrency         = $obj->fk_multicurrency;
635
                $this->multicurrency_code = $obj->multicurrency_code;
636
                $this->multicurrency_tx         = $obj->multicurrency_tx;
637
                $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
638
                $this->multicurrency_total_tva  = $obj->multicurrency_total_tva;
639
                $this->multicurrency_total_ttc  = $obj->multicurrency_total_ttc;
640
641
                // Retrieve all extrafield
642
                // fetch optionals attributes and labels
643
                if (empty($noextrafields)) {
644
                    $result = $this->fetch_optionals();
645
                    if ($result < 0) {
646
                        $this->error = $this->db->lasterror();
647
                        return -4;
648
                    }
649
                }
650
651
                // Retrieve lines
652
                if (empty($nolines)) {
653
                    $result = $this->fetch_lines();
654
                    if ($result < 0) {
655
                        $this->error = $this->db->lasterror();
656
                        return -3;
657
                    }
658
                }
659
660
                return 1;
661
            } else {
662
                $this->error = 'Bill with id ' . $rowid . ' or ref ' . $ref . ' not found';
663
                dol_syslog('Facture::Fetch Error ' . $this->error, LOG_ERR);
664
                return -2;
665
            }
666
        } else {
667
            $this->error = $this->db->error();
668
            return -1;
669
        }
670
    }
671
672
673
    /**
674
     *  Create an array of invoice lines
675
     *
676
     *  @return int     >0 if OK, <0 if KO
677
     */
678
    public function getLinesArray()
679
    {
680
        return $this->fetch_lines();
681
    }
682
683
684
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
685
    /**
686
     *  Get lines of template invoices into this->lines
687
     *
688
     *  @return     int         1 if OK, < 0 if KO
689
     */
690
    public function fetch_lines()
691
    {
692
		// phpcs:enable
693
694
        $this->lines = array();
695
696
        dol_syslog('FactureRec::fetch_lines', LOG_DEBUG);
697
698
        $sql = 'SELECT l.rowid, l.fk_facture, l.fk_product, l.fk_parent_line, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx, ';
699
        $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
700
        $sql .= ' l.info_bits, l.date_start_fill, l.date_end_fill, l.total_ht, l.total_tva, l.total_ttc, l.fk_product_fournisseur_price, l.buy_price_ht as pa_ht,';
701
        $sql .= ' l.rang, l.special_code,';
702
        $sql .= ' l.fk_unit, l.fk_contract_line,';
703
        $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
704
        $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
705
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facturedet_rec as l';
706
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product as p ON l.fk_product = p.rowid';
707
        $sql .= ' WHERE l.fk_facture = ' . ((int) $this->id);
708
        $sql .= ' ORDER BY l.rang';
709
710
        $result = $this->db->query($sql);
711
        if ($result) {
712
            $num = $this->db->num_rows($result);
713
            $i = 0;
714
            while ($i < $num) {
715
                $objp = $this->db->fetch_object($result);
716
                $line = new FactureLigneRec($this->db);
717
718
                $line->id               = $objp->rowid;
719
                $line->rowid            = $objp->rowid;
0 ignored issues
show
Deprecated Code introduced by
The property CommonObjectLine::$rowid has been deprecated: Try to use id property as possible (even if field into database is still rowid) ( Ignorable by Annotation )

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

719
                /** @scrutinizer ignore-deprecated */ $line->rowid            = $objp->rowid;

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...
720
                $line->fk_facture       = $objp->fk_facture;
721
                $line->fk_parent_line   = $objp->fk_parent_line;
722
                $line->desc             = $objp->description; // Description line
723
                $line->description      = $objp->description; // Description line
724
                $line->ref              = $objp->product_ref; // Ref product
725
                $line->product_ref      = $objp->product_ref; // Ref product
726
                $line->libelle          = $objp->product_label; // deprecated
727
                $line->product_label    = $objp->product_label; // Label product
728
                $line->product_desc     = $objp->product_desc; // Description product
729
                $line->product_type     = $objp->product_type; // Type of line
730
                $line->fk_product_type  = $objp->fk_product_type; // Type of product
731
                $line->qty              = $objp->qty;
732
                $line->subprice         = $objp->subprice;
733
734
                $line->label            = $objp->custom_label; // @deprecated
735
736
                $line->vat_src_code     = $objp->vat_src_code;
737
                $line->tva_tx           = $objp->tva_tx;
738
                $line->localtax1_tx     = $objp->localtax1_tx;
739
                $line->localtax2_tx     = $objp->localtax2_tx;
740
                $line->localtax1_type   = $objp->localtax1_type;
741
                $line->localtax2_type   = $objp->localtax2_type;
742
                $line->remise_percent   = $objp->remise_percent;
743
                //$line->fk_remise_except = $objp->fk_remise_except;
744
                $line->fk_product       = $objp->fk_product;
745
                $line->date_start_fill  = $objp->date_start_fill;
746
                $line->date_end_fill    = $objp->date_end_fill;
747
                $line->info_bits        = $objp->info_bits;
748
                $line->total_ht         = $objp->total_ht;
749
                $line->total_tva        = $objp->total_tva;
750
                $line->total_ttc        = $objp->total_ttc;
751
752
                $line->fk_product_fournisseur_price = $objp->fk_product_fournisseur_price;
753
                $line->fk_fournprice = $objp->fk_product_fournisseur_price; // For backward compatibility
754
755
                $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $objp->fk_product_fournisseur_price, $objp->pa_ht);
756
757
                $line->buyprice         = $marginInfos[0];
758
                $line->pa_ht            = $marginInfos[0]; // For backward compatibility
759
                $line->marge_tx         = $marginInfos[1];
760
                $line->marque_tx        = $marginInfos[2];
761
                $line->rang             = $objp->rang;
762
                $line->special_code     = $objp->special_code;
763
                $line->fk_unit          = $objp->fk_unit;
764
                $line->fk_contract_line = $objp->fk_contract_line;
765
766
                // Ne plus utiliser
767
                $line->price            = $objp->price;
768
                $line->remise           = $objp->remise;
769
770
                $line->fetch_optionals();
771
772
                // Multicurrency
773
                $line->fk_multicurrency = $objp->fk_multicurrency;
774
                $line->multicurrency_code = $objp->multicurrency_code;
775
                $line->multicurrency_subprice   = $objp->multicurrency_subprice;
776
                $line->multicurrency_total_ht   = $objp->multicurrency_total_ht;
777
                $line->multicurrency_total_tva  = $objp->multicurrency_total_tva;
778
                $line->multicurrency_total_ttc  = $objp->multicurrency_total_ttc;
779
780
                $this->lines[$i] = $line;
781
782
                $i++;
783
            }
784
785
            $this->db->free($result);
786
            return 1;
787
        } else {
788
            $this->error = $this->db->lasterror();
789
            return -3;
790
        }
791
    }
792
793
794
    /**
795
     *  Delete template invoice
796
     *
797
     *  @param      User    $user           User that delete.
798
     *  @param      int     $notrigger      1=Does not execute triggers, 0= execute triggers
799
     *  @param      int     $idwarehouse    Id warehouse to use for stock change.
800
     *  @return     int                     Return integer <0 if KO, >0 if OK
801
     */
802
    public function delete(User $user, $notrigger = 0, $idwarehouse = -1)
803
    {
804
        $rowid = $this->id;
805
806
        dol_syslog(get_class($this) . "::delete rowid=" . ((int) $rowid), LOG_DEBUG);
807
808
        $error = 0;
809
        $this->db->begin();
810
811
        $main = MAIN_DB_PREFIX . 'facturedet_rec';
812
        $ef = $main . "_extrafields";
813
814
        $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM " . $main . " WHERE fk_facture = " . ((int) $rowid) . ")";
815
        $sql = "DELETE FROM " . MAIN_DB_PREFIX . "facturedet_rec WHERE fk_facture = " . ((int) $rowid);
816
817
        if ($this->db->query($sqlef) && $this->db->query($sql)) {
818
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "facture_rec WHERE rowid = " . ((int) $rowid);
819
            dol_syslog($sql);
820
            if ($this->db->query($sql)) {
821
                // Delete linked object
822
                $res = $this->deleteObjectLinked();
823
                if ($res < 0) {
824
                    $error = -3;
825
                }
826
                // Delete extrafields
827
                $res = $this->deleteExtraFields();
828
                if ($res < 0) {
829
                    $error = -4;
830
                }
831
            } else {
832
                $this->error = $this->db->lasterror();
833
                $error = -1;
834
            }
835
        } else {
836
            $this->error = $this->db->lasterror();
837
            $error = -2;
838
        }
839
        if (!$error && !$notrigger) {
840
            // Call trigger
841
            $result = $this->call_trigger('BILLREC_DELETE', $user);
842
            if ($result < 0) {
843
                $error++;
844
            }
845
            // End call triggers
846
        }
847
        if (!$error) {
848
            $this->db->commit();
849
            return 1;
850
        } else {
851
            $this->db->rollback();
852
            return $error;
853
        }
854
    }
855
856
857
    /**
858
     *  Add a line to invoice
859
     *
860
     *  @param      string      $desc               Description de la ligne
861
     *  @param      double      $pu_ht              Prix unitaire HT (> 0 even for credit note)
862
     *  @param      double      $qty                Quantite
863
     *  @param      double      $txtva              Taux de tva force, sinon -1
864
     *  @param      double      $txlocaltax1        Local tax 1 rate (deprecated)
865
     *  @param      double      $txlocaltax2        Local tax 2 rate (deprecated)
866
     *  @param      int         $fk_product         Product/Service ID predefined
867
     *  @param      double      $remise_percent     Percentage discount of the line
868
     *  @param      string      $price_base_type    HT or TTC
869
     *  @param      int         $info_bits          VAT npr or not ?
870
     *  @param      int         $fk_remise_except   Id remise
871
     *  @param      double      $pu_ttc             Prix unitaire TTC (> 0 even for credit note)
872
     *  @param      int         $type               Type of line (0=product, 1=service)
873
     *  @param      int         $rang               Position of line
874
     *  @param      int         $special_code       Special code
875
     *  @param      string      $label              Label of the line
876
     *  @param      string      $fk_unit            Unit
877
     *  @param      double      $pu_ht_devise       Unit price in currency
878
     *  @param      int         $date_start_fill    1=Flag to fill start date when generating invoice
879
     *  @param      int         $date_end_fill      1=Flag to fill end date when generating invoice
880
     *  @param      int         $fk_fournprice      Supplier price id (to calculate margin) or ''
881
     *  @param      int         $pa_ht              Buying price of line (to calculate margin) or ''
882
     *  @param      int         $fk_parent_line     Id of parent line
883
     *  @return     int                             Return integer <0 if KO, Id of line if OK
884
     */
885
    public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $price_base_type = 'HT', $info_bits = 0, $fk_remise_except = 0, $pu_ttc = 0, $type = 0, $rang = -1, $special_code = 0, $label = '', $fk_unit = null, $pu_ht_devise = 0, $date_start_fill = 0, $date_end_fill = 0, $fk_fournprice = null, $pa_ht = 0, $fk_parent_line = 0)
886
    {
887
        global $mysoc;
888
889
        $facid = $this->id;
890
891
        dol_syslog(get_class($this) . "::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,txlocaltax1=$txlocaltax1,txlocaltax2=$txlocaltax2,fk_product=$fk_product,remise_percent=$remise_percent,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit,pu_ht_devise=$pu_ht_devise,date_start_fill=$date_start_fill,date_end_fill=$date_end_fill,pa_ht=$pa_ht", LOG_DEBUG);
892
        include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php';
893
894
        // Check parameters
895
        if ($type < 0) {
896
            return -1;
897
        }
898
899
        $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
900
901
        // Clean vat code
902
        $reg = array();
903
        $vat_src_code = '';
904
        if (preg_match('/\((.*)\)/', (string) $txtva, $reg)) {
905
            $vat_src_code = $reg[1];
906
            $txtva = preg_replace('/\s*\(.*\)/', '', (string) $txtva); // Remove code from vatrate.
907
        }
908
909
910
        // Clean parameters
911
        $remise_percent = price2num($remise_percent);
912
        if (empty($remise_percent)) {
913
            $remise_percent = 0;
914
        }
915
        $qty = price2num($qty);
916
        $pu_ht = price2num($pu_ht);
917
        $pu_ttc = price2num($pu_ttc);
918
        if (!preg_match('/\((.*)\)/', $txtva)) {
919
            $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
920
        }
921
        $txlocaltax1 = price2num($txlocaltax1);
922
        $txlocaltax2 = price2num($txlocaltax2);
923
        if (empty($txtva)) {
924
            $txtva = 0;
925
        }
926
        if (empty($txlocaltax1)) {
927
            $txlocaltax1 = 0;
928
        }
929
        if (empty($txlocaltax2)) {
930
            $txlocaltax2 = 0;
931
        }
932
        if (empty($info_bits)) {
933
            $info_bits = 0;
934
        }
935
936
        if ($price_base_type == 'HT') {
937
            $pu = $pu_ht;
938
        } else {
939
            $pu = $pu_ttc;
940
        }
941
942
        // Calcul du total TTC et de la TVA pour la ligne a partir de
943
        // qty, pu, remise_percent et txtva
944
        // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
945
        // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
946
947
        $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
948
        $total_ht  = $tabprice[0];
949
        $total_tva = $tabprice[1];
950
        $total_ttc = $tabprice[2];
951
        $total_localtax1 = $tabprice[9];
952
        $total_localtax2 = $tabprice[10];
953
        $pu_ht = $tabprice[3];
954
955
        // MultiCurrency
956
        $multicurrency_total_ht  = $tabprice[16];
957
        $multicurrency_total_tva = $tabprice[17];
958
        $multicurrency_total_ttc = $tabprice[18];
959
        $pu_ht_devise = $tabprice[19];
960
961
        $product_type = $type;
962
        if ($fk_product) {
963
            $product = new Product($this->db);
964
            $result = $product->fetch($fk_product);
965
            $product_type = $product->type;
966
        }
967
968
        if (empty($fk_parent_line) || $fk_parent_line < 0) {
969
            $fk_parent_line = 0;
970
        }
971
972
        // Rank to use
973
        $ranktouse = $rang;
974
        if ($ranktouse == -1) {
975
            $rangmax = $this->line_max(0);
976
            $ranktouse = $rangmax + 1;
977
        }
978
979
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "facturedet_rec (";
980
        $sql .= "fk_facture";
981
        $sql .= ", fk_parent_line";
982
        $sql .= ", label";
983
        $sql .= ", description";
984
        $sql .= ", price";
985
        $sql .= ", qty";
986
        $sql .= ", tva_tx";
987
        $sql .= ", vat_src_code";
988
        $sql .= ", localtax1_tx";
989
        $sql .= ", localtax1_type";
990
        $sql .= ", localtax2_tx";
991
        $sql .= ", localtax2_type";
992
        $sql .= ", fk_product";
993
        $sql .= ", product_type";
994
        $sql .= ", remise_percent";
995
        $sql .= ", subprice";
996
        $sql .= ", remise";
997
        $sql .= ", total_ht";
998
        $sql .= ", total_tva";
999
        $sql .= ", total_localtax1";
1000
        $sql .= ", total_localtax2";
1001
        $sql .= ", total_ttc";
1002
        $sql .= ", date_start_fill";
1003
        $sql .= ", date_end_fill";
1004
        $sql .= ", fk_product_fournisseur_price";
1005
        $sql .= ", buy_price_ht";
1006
        $sql .= ", info_bits";
1007
        $sql .= ", rang";
1008
        $sql .= ", special_code";
1009
        $sql .= ", fk_unit";
1010
        $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
1011
        $sql .= ") VALUES (";
1012
        $sql .= " " . ((int) $facid);
1013
        $sql .= ", " . ($fk_parent_line > 0 ? ((int) $fk_parent_line) : "null");
1014
        $sql .= ", " . (!empty($label) ? "'" . $this->db->escape($label) . "'" : "null");
1015
        $sql .= ", '" . $this->db->escape($desc) . "'";
1016
        $sql .= ", " . price2num($pu_ht);
1017
        $sql .= ", " . price2num($qty);
1018
        $sql .= ", " . price2num($txtva);
1019
        $sql .= ", '" . $this->db->escape($vat_src_code) . "'";
1020
        $sql .= ", " . price2num($txlocaltax1);
1021
        $sql .= ", '" . $this->db->escape(isset($localtaxes_type[0]) ? $localtaxes_type[0] : '') . "'";
1022
        $sql .= ", " . price2num($txlocaltax2);
1023
        $sql .= ", '" . $this->db->escape(isset($localtaxes_type[2]) ? $localtaxes_type[2] : '') . "'";
1024
        $sql .= ", " . (!empty($fk_product) ? "'" . $this->db->escape($fk_product) . "'" : "null");
1025
        $sql .= ", " . ((int) $product_type);
1026
        $sql .= ", " . price2num($remise_percent);
1027
        $sql .= ", " . price2num($pu_ht);
1028
        $sql .= ", null";
1029
        $sql .= ", " . price2num($total_ht);
1030
        $sql .= ", " . price2num($total_tva);
1031
        $sql .= ", " . price2num($total_localtax1);
1032
        $sql .= ", " . price2num($total_localtax2);
1033
        $sql .= ", " . price2num($total_ttc);
1034
        $sql .= ", " . (int) $date_start_fill;
1035
        $sql .= ", " . (int) $date_end_fill;
1036
        $sql .= ", " . ($fk_fournprice > 0 ? $fk_fournprice : 'null');
1037
        $sql .= ", " . ($pa_ht ? price2num($pa_ht) : 0);
1038
        $sql .= ", " . ((int) $info_bits);
1039
        $sql .= ", " . ((int) $ranktouse);
1040
        $sql .= ", " . ((int) $special_code);
1041
        $sql .= ", " . ($fk_unit ? ((int) $fk_unit) : "null");
1042
        $sql .= ", " . (int) $this->fk_multicurrency;
1043
        $sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'";
1044
        $sql .= ", " . price2num($pu_ht_devise, 'CU');
1045
        $sql .= ", " . price2num($multicurrency_total_ht, 'CT');
1046
        $sql .= ", " . price2num($multicurrency_total_tva, 'CT');
1047
        $sql .= ", " . price2num($multicurrency_total_ttc, 'CT');
1048
        $sql .= ")";
1049
1050
        dol_syslog(get_class($this) . "::addline", LOG_DEBUG);
1051
        if ($this->db->query($sql)) {
1052
            $lineId = $this->db->last_insert_id(MAIN_DB_PREFIX . "facturedet_rec");
1053
            $this->id = $facid;
1054
            $this->update_price(1);
1055
            return $lineId;
1056
        } else {
1057
            $this->error = $this->db->lasterror();
1058
            return -1;
1059
        }
1060
    }
1061
1062
    /**
1063
     *  Update a line to invoice
1064
     *
1065
     *  @param      int         $rowid              Id of line to update
1066
     *  @param      string      $desc               Description de la ligne
1067
     *  @param      double      $pu_ht              Prix unitaire HT (> 0 even for credit note)
1068
     *  @param      double      $qty                Quantite
1069
     *  @param      double      $txtva              Taux de tva force, sinon -1
1070
     *  @param      double      $txlocaltax1        Local tax 1 rate (deprecated)
1071
     *  @param      double      $txlocaltax2        Local tax 2 rate (deprecated)
1072
     *  @param      int         $fk_product         Product/Service ID predefined
1073
     *  @param      double      $remise_percent     Percentage discount of the line
1074
     *  @param      string      $price_base_type    HT or TTC
1075
     *  @param      int         $info_bits          Bits of type of lines
1076
     *  @param      int         $fk_remise_except   Id remise
1077
     *  @param      double      $pu_ttc             Prix unitaire TTC (> 0 even for credit note)
1078
     *  @param      int         $type               Type of line (0=product, 1=service)
1079
     *  @param      int         $rang               Position of line
1080
     *  @param      int         $special_code       Special code
1081
     *  @param      string      $label              Label of the line
1082
     *  @param      string      $fk_unit            Unit
1083
     *  @param      double      $pu_ht_devise       Unit price in currency
1084
     *  @param      int         $notrigger          disable line update trigger
1085
     *  @param      int         $date_start_fill    1=Flag to fill start date when generating invoice
1086
     *  @param      int         $date_end_fill      1=Flag to fill end date when generating invoice
1087
     *  @param      int         $fk_fournprice      Id of origin supplier price
1088
     *  @param      int         $pa_ht              Price (without tax) of product for margin calculation
1089
     *  @param      int         $fk_parent_line     Id of parent line
1090
     *  @return     int                             Return integer <0 if KO, Id of line if OK
1091
     */
1092
    public function updateline($rowid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $price_base_type = 'HT', $info_bits = 0, $fk_remise_except = 0, $pu_ttc = 0, $type = 0, $rang = -1, $special_code = 0, $label = '', $fk_unit = null, $pu_ht_devise = 0, $notrigger = 0, $date_start_fill = 0, $date_end_fill = 0, $fk_fournprice = null, $pa_ht = 0, $fk_parent_line = 0)
1093
    {
1094
        global $mysoc;
1095
1096
        $facid = $this->id;
1097
1098
        dol_syslog(get_class($this) . "::updateline facid=" . $facid . " rowid=$rowid, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, txlocaltax1=$txlocaltax1, txlocaltax2=$txlocaltax2, fk_product=$fk_product, remise_percent=$remise_percent, info_bits=$info_bits, fk_remise_except=$fk_remise_except, price_base_type=$price_base_type, pu_ttc=$pu_ttc, type=$type, fk_unit=$fk_unit, pu_ht_devise=$pu_ht_devise", LOG_DEBUG);
1099
        include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php';
1100
1101
        // Clean parameters
1102
        if (empty($remise_percent)) {
1103
            $remise_percent = 0;
1104
        }
1105
1106
        // Check parameters
1107
        if ($type < 0) {
1108
            return -1;
1109
        }
1110
1111
        // Clean parameters
1112
        $remise_percent = price2num($remise_percent);
1113
        $qty = price2num($qty);
1114
        if (empty($info_bits)) {
1115
            $info_bits = 0;
1116
        }
1117
        $pu_ht          = price2num($pu_ht);
1118
        $pu_ttc         = price2num($pu_ttc);
1119
        $pu_ht_devise = price2num($pu_ht_devise);
1120
        if (!preg_match('/\((.*)\)/', (string) $txtva)) {
1121
            $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1122
        }
1123
        $txlocaltax1    = price2num($txlocaltax1);
1124
        $txlocaltax2    = price2num($txlocaltax2);
1125
        if (empty($txlocaltax1)) {
1126
            $txlocaltax1 = 0;
1127
        }
1128
        if (empty($txlocaltax2)) {
1129
            $txlocaltax2 = 0;
1130
        }
1131
1132
        if (empty($this->multicurrency_subprice)) {
1133
            $this->multicurrency_subprice = 0;
1134
        }
1135
        if (empty($this->multicurrency_total_ht)) {
1136
            $this->multicurrency_total_ht = 0;
1137
        }
1138
        if (empty($this->multicurrency_total_tva)) {
1139
            $this->multicurrency_total_tva = 0;
1140
        }
1141
        if (empty($this->multicurrency_total_ttc)) {
1142
            $this->multicurrency_total_ttc = 0;
1143
        }
1144
1145
        if ($price_base_type == 'HT') {
1146
            $pu = $pu_ht;
1147
        } else {
1148
            $pu = $pu_ttc;
1149
        }
1150
1151
        // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
1152
        // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1153
        // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1154
1155
        $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1156
1157
        // Clean vat code
1158
        $vat_src_code = '';
1159
        $reg = array();
1160
        if (preg_match('/\((.*)\)/', $txtva, $reg)) {
1161
            $vat_src_code = $reg[1];
1162
            $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1163
        }
1164
1165
        $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1166
1167
        $total_ht  = $tabprice[0];
1168
        $total_tva = $tabprice[1];
1169
        $total_ttc = $tabprice[2];
1170
        $total_localtax1 = $tabprice[9];
1171
        $total_localtax2 = $tabprice[10];
1172
        $pu_ht  = $tabprice[3];
1173
        $pu_tva = $tabprice[4];
1174
        $pu_ttc = $tabprice[5];
1175
1176
        // MultiCurrency
1177
        $multicurrency_total_ht  = $tabprice[16];
1178
        $multicurrency_total_tva = $tabprice[17];
1179
        $multicurrency_total_ttc = $tabprice[18];
1180
        $pu_ht_devise = $tabprice[19];
1181
1182
        $product_type = $type;
1183
        if ($fk_product) {
1184
            $product = new Product($this->db);
1185
            $result = $product->fetch($fk_product);
1186
            $product_type = $product->type;
1187
        }
1188
1189
        if (empty($fk_parent_line) || $fk_parent_line < 0) {
1190
            $fk_parent_line = 0;
1191
        }
1192
1193
        $sql = "UPDATE " . MAIN_DB_PREFIX . "facturedet_rec SET ";
1194
        $sql .= "fk_facture = " . ((int) $facid);
1195
        $sql .= ", fk_parent_line = " . ($fk_parent_line > 0 ? ((int) $fk_parent_line) : "null");
1196
        $sql .= ", label=" . (!empty($label) ? "'" . $this->db->escape($label) . "'" : "null");
1197
        $sql .= ", description='" . $this->db->escape($desc) . "'";
1198
        $sql .= ", price=" . price2num($pu_ht);
1199
        $sql .= ", qty=" . price2num($qty);
1200
        $sql .= ", tva_tx=" . price2num($txtva);
1201
        $sql .= ", vat_src_code='" . $this->db->escape($vat_src_code) . "'";
1202
        $sql .= ", localtax1_tx=" . ((float) $txlocaltax1);
1203
        $sql .= ", localtax1_type='" . $this->db->escape($localtaxes_type[0]) . "'";
1204
        $sql .= ", localtax2_tx=" . ((float) $txlocaltax2);
1205
        $sql .= ", localtax2_type='" . $this->db->escape($localtaxes_type[2]) . "'";
1206
        $sql .= ", fk_product=" . (!empty($fk_product) ? "'" . $this->db->escape($fk_product) . "'" : "null");
1207
        $sql .= ", product_type=" . ((int) $product_type);
1208
        $sql .= ", remise_percent='" . price2num($remise_percent) . "'";
1209
        $sql .= ", subprice='" . price2num($pu_ht) . "'";
1210
        $sql .= ", total_ht='" . price2num($total_ht) . "'";
1211
        $sql .= ", total_tva='" . price2num($total_tva) . "'";
1212
        $sql .= ", total_localtax1='" . price2num($total_localtax1) . "'";
1213
        $sql .= ", total_localtax2='" . price2num($total_localtax2) . "'";
1214
        $sql .= ", total_ttc='" . price2num($total_ttc) . "'";
1215
        $sql .= ", date_start_fill=" . ((int) $date_start_fill);
1216
        $sql .= ", date_end_fill=" . ((int) $date_end_fill);
1217
        $sql .= ", fk_product_fournisseur_price=" . ($fk_fournprice > 0 ? $fk_fournprice : 'null');
1218
        $sql .= ", buy_price_ht=" . ($pa_ht ? price2num($pa_ht) : 0);
1219
        $sql .= ", info_bits=" . ((int) $info_bits);
1220
        $sql .= ", rang=" . ((int) $rang);
1221
        $sql .= ", special_code=" . ((int) $special_code);
1222
        $sql .= ", fk_unit=" . ($fk_unit ? "'" . $this->db->escape($fk_unit) . "'" : "null");
1223
        $sql .= ', multicurrency_subprice = ' . price2num($pu_ht_devise);
1224
        $sql .= ', multicurrency_total_ht = ' . price2num($multicurrency_total_ht);
1225
        $sql .= ', multicurrency_total_tva = ' . price2num($multicurrency_total_tva);
1226
        $sql .= ', multicurrency_total_ttc = ' . price2num($multicurrency_total_ttc);
1227
        $sql .= " WHERE rowid = " . ((int) $rowid);
1228
1229
        dol_syslog(get_class($this) . "::updateline", LOG_DEBUG);
1230
        if ($this->db->query($sql)) {
1231
            $this->id = $facid;
1232
            $this->update_price(1);
1233
            return 1;
1234
        } else {
1235
            $this->error = $this->db->lasterror();
1236
            return -1;
1237
        }
1238
    }
1239
1240
1241
    /**
1242
     * Return the next date of
1243
     *
1244
     * @return  int|false   false if KO, timestamp if OK
1245
     */
1246
    public function getNextDate()
1247
    {
1248
        if (empty($this->date_when)) {
1249
            return false;
1250
        }
1251
        return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency);
1252
    }
1253
1254
    /**
1255
     * Return if maximum number of generation is reached
1256
     *
1257
     * @return  boolean         False by default, True if maximum number of generation is reached
1258
     */
1259
    public function isMaxNbGenReached()
1260
    {
1261
        $ret = false;
1262
        if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) {
1263
            $ret = true;
1264
        }
1265
        return $ret;
1266
    }
1267
1268
    /**
1269
     * Format string to output with by striking the string if max number of generation was reached
1270
     *
1271
     * @param   string      $ret    Default value to output
1272
     * @return  string              html formatted string
1273
     */
1274
    public function strikeIfMaxNbGenReached($ret)
1275
    {
1276
        return $this->isMaxNbGenReached() ? '<strike>' . $ret . '</strike>' : $ret;
1277
    }
1278
1279
    /**
1280
     *  Create all recurrents invoices (for all entities if multicompany is used).
1281
     *  A result may also be provided into this->output.
1282
     *
1283
     *  WARNING: This method change temporarily context $conf->entity to be in correct context for each recurring invoice found.
1284
     *
1285
     *  @param  int     $restrictioninvoiceid       0=All qualified template invoices found. > 0 = restrict action on invoice ID
1286
     *  @param  int     $forcevalidation        1=Force validation of invoice whatever is template auto_validate flag.
1287
     *  @param      int     $notrigger          Disable the trigger
1288
     *  @return int                             0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
1289
     */
1290
    public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0, $notrigger = 0)
1291
    {
1292
        global $conf, $langs, $db, $user, $hookmanager;
1293
1294
        $error = 0;
1295
        $nb_create = 0;
1296
1297
        // Load translation files required by the page
1298
        $langs->loadLangs(array("main", "bills"));
1299
1300
        $now = dol_now();
1301
        $tmparray = dol_getdate($now);
1302
        $today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day
1303
1304
        $this->output = '';
1305
1306
        dol_syslog("createRecurringInvoices restrictioninvoiceid=" . $restrictioninvoiceid . " forcevalidation=" . $forcevalidation);
1307
1308
        $sql = 'SELECT rowid FROM ' . MAIN_DB_PREFIX . 'facture_rec';
1309
        $sql .= ' WHERE frequency > 0'; // A recurring invoice is an invoice with a frequency
1310
        $sql .= " AND (date_when IS NULL OR date_when <= '" . $this->db->idate($today) . "')";
1311
        $sql .= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
1312
        $sql .= ' AND suspended = 0';
1313
        $sql .= ' AND entity = ' . $conf->entity; // MUST STAY = $conf->entity here
1314
        if ($restrictioninvoiceid > 0) {
1315
            $sql .= ' AND rowid = ' . ((int) $restrictioninvoiceid);
1316
        }
1317
        $sql .= $this->db->order('entity', 'ASC');
1318
        //print $sql;exit;
1319
        $parameters = array(
1320
            'restrictioninvoiceid' => $restrictioninvoiceid,
1321
            'forcevalidation' => $forcevalidation,
1322
        );
1323
        $reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks
1324
1325
        $resql = $this->db->query($sql);
1326
        if ($resql) {
1327
            $i = 0;
1328
            $num = $this->db->num_rows($resql);
1329
1330
            if ($num) {
1331
                $this->output .= $langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num) . "\n";
1332
            } else {
1333
                $this->output .= $langs->trans("NoQualifiedRecurringInvoiceTemplateFound");
1334
            }
1335
1336
            $saventity = $conf->entity;
1337
1338
            while ($i < $num) {     // Loop on each template invoice. If $num = 0, test is false at first pass.
1339
                $line = $this->db->fetch_object($resql);
1340
1341
                $this->db->begin();
1342
1343
                $invoiceidgenerated = 0;
1344
1345
                $facture = null;
1346
                $facturerec = new FactureRec($this->db);
1347
                $facturerec->fetch($line->rowid);
1348
1349
                if ($facturerec->id > 0) {
1350
                    // Set entity context
1351
                    $conf->entity = $facturerec->entity;
1352
1353
                    dol_syslog("createRecurringInvoices Process invoice template id=" . $facturerec->id . ", ref=" . $facturerec->ref . ", entity=" . $facturerec->entity);
1354
1355
                    $facture = new Facture($this->db);
1356
                    $facture->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice
1357
                    $facture->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice
1358
1359
                    $facture->type = self::TYPE_STANDARD;
1360
                    $facture->subtype = $facturerec->subtype;
1361
                    $facture->statut = self::STATUS_DRAFT;  // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

1361
                    /** @scrutinizer ignore-deprecated */ $facture->statut = self::STATUS_DRAFT;  // deprecated

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...
1362
                    $facture->status = self::STATUS_DRAFT;
1363
                    $facture->date = (empty($facturerec->date_when) ? $now : $facturerec->date_when); // We could also use dol_now here but we prefer date_when so invoice has real date when we would like even if we generate later.
1364
                    $facture->socid = $facturerec->socid;
1365
                    if (!empty($facturerec->fk_multicurrency)) {
1366
                        $facture->fk_multicurrency = $facturerec->fk_multicurrency;
1367
                        $facture->multicurrency_code = $facturerec->multicurrency_code;
1368
                        $facture->multicurrency_tx = $facturerec->multicurrency_tx;
1369
                    }
1370
1371
                    $invoiceidgenerated = $facture->create($user);
1372
                    if ($invoiceidgenerated <= 0) {
1373
                        $this->errors = $facture->errors;
1374
                        $this->error = $facture->error;
1375
                        $error++;
1376
                    }
1377
1378
1379
                    if (!$error && ($facturerec->auto_validate || $forcevalidation)) {
1380
                        $result = $facture->validate($user);
1381
                        if ($result <= 0) {
1382
                            $this->errors = $facture->errors;
1383
                            $this->error = $facture->error;
1384
                            $error++;
1385
                        }
1386
                    }
1387
                    if (!$error && $facturerec->generate_pdf) {
1388
                        // We refresh the object in order to have all necessary data (like date_lim_reglement)
1389
                        $facture->fetch($facture->id);
1390
                        $result = $facture->generateDocument($facturerec->model_pdf, $langs);
1391
                        if ($result <= 0) {
1392
                            $this->errors = $facture->errors;
1393
                            $this->error = $facture->error;
1394
                            $error++;
1395
                        }
1396
                    }
1397
                } else {
1398
                    $error++;
1399
                    $this->error = "Failed to load invoice template with id=" . $line->rowid . ", entity=" . $conf->entity . "\n";
1400
                    $this->errors[] = "Failed to load invoice template with id=" . $line->rowid . ", entity=" . $conf->entity;
1401
                    dol_syslog("createRecurringInvoices Failed to load invoice template with id=" . $line->rowid . ", entity=" . $conf->entity);
1402
                }
1403
1404
                if (!$error && $invoiceidgenerated >= 0) {
1405
                    $this->db->commit("createRecurringInvoices Process invoice template id=" . $facturerec->id . ", ref=" . $facturerec->ref);
1406
                    dol_syslog("createRecurringInvoices Process invoice template " . $facturerec->ref . " is finished with a success generation");
1407
                    $nb_create++;
1408
                    $this->output .= $langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref) . "\n";
1409
                } else {
1410
                    $this->db->rollback("createRecurringInvoices Process invoice template id=" . $facturerec->id . ", ref=" . $facturerec->ref);
1411
                }
1412
1413
                $parameters = array(
1414
                    'cpt'        => $i,
1415
                    'total'      => $num,
1416
                    'errorCount' => $error,
1417
                    'invoiceidgenerated' => $invoiceidgenerated,
1418
                    'facturerec' => $facturerec, // it's an object which PHP passes by "reference", so modifiable by hooks.
1419
                    'this'       => $this, // it's an object which PHP passes by "reference", so modifiable by hooks.
1420
                );
1421
                $reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $facture); // note: $facture can be modified by hooks (warning: $facture can be null)
1422
1423
                $i++;
1424
            }
1425
1426
            $conf->entity = $saventity; // Restore entity context
1427
        } else {
1428
            dol_print_error($this->db);
1429
        }
1430
1431
        $this->output = trim($this->output);
1432
1433
        return $error ? $error : 0;
1434
    }
1435
1436
    /**
1437
     *  Return clicable name (with picto eventually)
1438
     *
1439
     * @param   int     $withpicto                  Add picto into link
1440
     * @param  string   $option                     Where point the link
1441
     * @param  int      $max                        Maxlength of ref
1442
     * @param  int      $short                      1=Return just URL
1443
     * @param  string   $moretitle                  Add more text to title tooltip
1444
     * @param   int     $notooltip                  1=Disable tooltip
1445
     * @param  int      $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
1446
     * @return string                               String with URL
1447
     */
1448
    public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1449
    {
1450
        global $langs, $hookmanager;
1451
1452
        $result = '';
1453
1454
        $label = img_picto('', $this->picto) . ' <u class="paddingrightonly">' . $langs->trans("RepeatableInvoice") . '</u>';
1455
        if (!empty($this->ref)) {
1456
            $label .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1457
        }
1458
        if ($this->frequency > 0) {
1459
            $label .= '<br><b>' . $langs->trans('Frequency') . ':</b> ' . $langs->trans('FrequencyPer_' . $this->unit_frequency, $this->frequency);
1460
        }
1461
        if (!empty($this->date_last_gen)) {
1462
            $label .= '<br><b>' . $langs->trans('DateLastGeneration') . ':</b> ' . dol_print_date($this->date_last_gen, 'dayhour');
1463
        }
1464
        if ($this->frequency > 0) {
1465
            if (!empty($this->date_when)) {
1466
                $label .= '<br><b>' . $langs->trans('NextDateToExecution') . ':</b> ';
1467
                $label .= (empty($this->suspended) ? '' : '<strike>') . dol_print_date($this->date_when, 'day') . (empty($this->suspended) ? '' : '</strike>'); // No hour for this property
1468
                if (!empty($this->suspended)) {
1469
                    $label .= ' (' . $langs->trans("Disabled") . ')';
1470
                }
1471
            }
1472
        }
1473
1474
        $url = constant('BASE_URL') . '/compta/facture/card-rec.php?facid=' . $this->id;
1475
1476
        if ($short) {
1477
            return $url;
1478
        }
1479
1480
        if ($option != 'nolink') {
1481
            // Add param to save lastsearch_values or not
1482
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1483
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1484
                $add_save_lastsearch_values = 1;
1485
            }
1486
            if ($add_save_lastsearch_values) {
1487
                $url .= '&save_lastsearch_values=1';
1488
            }
1489
        }
1490
1491
        $linkstart = '<a href="' . $url . '" title="' . dol_escape_htmltag($label, 1) . '" class="classfortooltip">';
1492
        $linkend = '</a>';
1493
1494
        $result .= $linkstart;
1495
        if ($withpicto) {
1496
            $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1497
        }
1498
        if ($withpicto != 2) {
1499
            $result .= $this->ref;
1500
        }
1501
        $result .= $linkend;
1502
        global $action;
1503
        $hookmanager->initHooks(array($this->element . 'dao'));
1504
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1505
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1506
        if ($reshook > 0) {
1507
            $result = $hookmanager->resPrint;
1508
        } else {
1509
            $result .= $hookmanager->resPrint;
1510
        }
1511
        return $result;
1512
    }
1513
1514
    /**
1515
     *  Return label of object status
1516
     *
1517
     *  @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
1518
     *  @param      integer $alreadypaid    Not used on recurring invoices
1519
     *  @return     string                  Label of status
1520
     */
1521
    public function getLibStatut($mode = 0, $alreadypaid = -1)
1522
    {
1523
        return $this->LibStatut($this->frequency ? 1 : 0, $this->suspended, $mode, $alreadypaid, empty($this->type) ? 0 : $this->type);
1524
    }
1525
1526
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1527
    /**
1528
     *  Return label of a status
1529
     *
1530
     *  @param      int     $recur          Is it a recurring invoice ?
1531
     *  @param      int     $status         Id status (suspended or not)
1532
     *  @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
1533
     *  @param      integer $alreadypaid    Not used for recurring invoices
1534
     *  @param      int     $type           Type invoice
1535
     *  @return     string                  Label of status
1536
     */
1537
    public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0)
1538
    {
1539
		// phpcs:enable
1540
        global $langs;
1541
        $langs->load('bills');
1542
1543
        $labelStatus = $langs->transnoentitiesnoconv('Active');
1544
        $statusType = 'status0';
1545
1546
        //print "$recur,$status,$mode,$alreadypaid,$type";
1547
        if ($mode == 0) {
1548
            if ($recur) {
1549
                if ($status == self::STATUS_SUSPENDED) {
1550
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1551
                } else {
1552
                    $labelStatus = $langs->transnoentitiesnoconv('Active');
1553
                }
1554
            } else {
1555
                if ($status == self::STATUS_SUSPENDED) {
1556
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1557
                } else {
1558
                    $labelStatus = $langs->transnoentitiesnoconv("Draft");
1559
                }
1560
            }
1561
        } elseif ($mode == 1) {
1562
            $prefix = 'Short';
1563
            if ($recur) {
1564
                if ($status == self::STATUS_SUSPENDED) {
1565
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1566
                } else {
1567
                    $labelStatus = $langs->transnoentitiesnoconv('Active');
1568
                }
1569
            } else {
1570
                if ($status == self::STATUS_SUSPENDED) {
1571
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1572
                } else {
1573
                    $labelStatus = $langs->transnoentitiesnoconv("Draft");
1574
                }
1575
            }
1576
        } elseif ($mode == 2) {
1577
            if ($recur) {
1578
                if ($status == self::STATUS_SUSPENDED) {
1579
                    $statusType = 'status6';
1580
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1581
                } else {
1582
                    $statusType = 'status4';
1583
                    $labelStatus = $langs->transnoentitiesnoconv('Active');
1584
                }
1585
            } else {
1586
                if ($status == self::STATUS_SUSPENDED) {
1587
                    $statusType = 'status6';
1588
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1589
                } else {
1590
                    $statusType = 'status0';
1591
                    $labelStatus = $langs->transnoentitiesnoconv('Draft');
1592
                }
1593
            }
1594
        } elseif ($mode == 3) {
1595
            if ($recur) {
1596
                $prefix = 'Short';
1597
                if ($status == self::STATUS_SUSPENDED) {
1598
                    $statusType = 'status6';
1599
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1600
                } else {
1601
                    $statusType = 'status4';
1602
                    $labelStatus = $langs->transnoentitiesnoconv('Active');
1603
                }
1604
            } else {
1605
                if ($status == self::STATUS_SUSPENDED) {
1606
                    $statusType = 'status6';
1607
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1608
                } else {
1609
                    $statusType = 'status0';
1610
                    $labelStatus = $langs->transnoentitiesnoconv('Draft');
1611
                }
1612
            }
1613
        } elseif ($mode == 4) {
1614
            $prefix = '';
1615
            if ($recur) {
1616
                if ($status == self::STATUS_SUSPENDED) {
1617
                    $statusType = 'status6';
1618
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1619
                } else {
1620
                    $statusType = 'status4';
1621
                    $labelStatus = $langs->transnoentitiesnoconv('Active');
1622
                }
1623
            } else {
1624
                if ($status == self::STATUS_SUSPENDED) {
1625
                    $statusType = 'status6';
1626
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1627
                } else {
1628
                    $statusType = 'status0';
1629
                    $labelStatus = $langs->transnoentitiesnoconv('Draft');
1630
                }
1631
            }
1632
        } elseif ($mode == 5 || $mode == 6) {
1633
            $prefix = '';
1634
            if ($mode == 5) {
1635
                $prefix = 'Short';
1636
            }
1637
            if ($recur) {
1638
                if ($status == self::STATUS_SUSPENDED) {
1639
                    $statusType = 'status6';
1640
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1641
                } else {
1642
                    $statusType = 'status4';
1643
                    $labelStatus = $langs->transnoentitiesnoconv('Active');
1644
                }
1645
            } else {
1646
                if ($status == self::STATUS_SUSPENDED) {
1647
                    $statusType = 'status6';
1648
                    $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1649
                } else {
1650
                    $statusType = 'status0';
1651
                    $labelStatus = $langs->transnoentitiesnoconv('Draft');
1652
                }
1653
            }
1654
        }
1655
1656
        $labelStatusShort = $labelStatus;
1657
1658
        return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1659
    }
1660
1661
    /**
1662
     * Return next reference of invoice not already used (or last reference)
1663
     *
1664
     * @param    Societe    $soc        Thirdparty object
1665
     * @param    string     $mode       'next' for next value or 'last' for last value
1666
     * @return   string                 free ref or last ref
1667
     */
1668
    public function getNextNumRef($soc, $mode = 'next')
1669
    {
1670
        // Not used for recurring invoices
1671
        return '';
1672
    }
1673
1674
    /**
1675
     *  Load miscellaneous information for tab "Info"
1676
     *
1677
     *  @param  int     $id     Id of object to load
1678
     *  @return void
1679
     */
1680
    public function info($id)
1681
    {
1682
        $sql = 'SELECT c.rowid, datec, tms as datem,';
1683
        $sql .= ' fk_user_author, fk_user_modif';
1684
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as c';
1685
        $sql .= ' WHERE c.rowid = ' . ((int) $id);
1686
1687
        $result = $this->db->query($sql);
1688
        if ($result) {
1689
            if ($this->db->num_rows($result)) {
1690
                $obj = $this->db->fetch_object($result);
1691
1692
                $this->id = $obj->rowid;
1693
1694
                $this->user_creation_id = $obj->fk_user_author;
1695
                $this->user_modification_id = $obj->fk_user_modif;
1696
                $this->date_creation     = $this->db->jdate($obj->datec);
1697
                $this->date_modification = $this->db->jdate($obj->datem);
1698
            }
1699
            $this->db->free($result);
1700
        } else {
1701
            dol_print_error($this->db);
1702
        }
1703
    }
1704
1705
    /**
1706
     *  Initialise an instance with random values.
1707
     *  Used to build previews or test instances.
1708
     *  id must be 0 if object instance is a specimen.
1709
     *
1710
     *  @param  string      $option     ''=Create a specimen invoice with lines, 'nolines'=No lines
1711
     *  @return int
1712
     */
1713
    public function initAsSpecimen($option = '')
1714
    {
1715
        global $langs;
1716
1717
        $now = dol_now();
1718
        $arraynow = dol_getdate($now);
1719
        $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1720
1721
        // Load array of products prodids
1722
        $num_prods = 0;
1723
        $prodids = array();
1724
1725
        $sql = "SELECT rowid";
1726
        $sql .= " FROM " . MAIN_DB_PREFIX . "product";
1727
        $sql .= " WHERE entity IN (" . getEntity('product') . ")";
1728
        $sql .= $this->db->plimit(100);
1729
1730
        $resql = $this->db->query($sql);
1731
        if ($resql) {
1732
            $num_prods = $this->db->num_rows($resql);
1733
            $i = 0;
1734
            while ($i < $num_prods) {
1735
                $i++;
1736
                $row = $this->db->fetch_row($resql);
1737
                $prodids[$i] = $row[0];
1738
            }
1739
        }
1740
1741
        // Initialize parameters
1742
        $this->id = 0;
1743
        $this->ref = 'SPECIMEN';
1744
        $this->title = 'SPECIMEN';
1745
        $this->specimen = 1;
1746
        $this->socid = 1;
1747
        $this->date = $nownotime;
1748
        $this->date_lim_reglement = $nownotime + 3600 * 24 * 30;
1749
        $this->cond_reglement_id   = 1;
1750
        $this->cond_reglement_code = 'RECEP';
1751
        $this->date_lim_reglement = $this->calculate_date_lim_reglement();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->calculate_date_lim_reglement() can also be of type string. However, the property $date_lim_reglement 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...
1752
        $this->mode_reglement_id   = 0; // Not forced to show payment mode CHQ + VIR
1753
        $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR
1754
        $this->note_public = 'This is a comment (public)';
1755
        $this->note_private = 'This is a comment (private)';
1756
        $this->note = 'This is a comment (private)';
0 ignored issues
show
Deprecated Code introduced by
The property CommonObject::$note has been deprecated: Use $note_private instead. ( Ignorable by Annotation )

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

1756
        /** @scrutinizer ignore-deprecated */ $this->note = 'This is a comment (private)';

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...
1757
        $this->fk_incoterms = 0;
1758
        $this->location_incoterms = '';
1759
1760
        if (empty($option) || $option != 'nolines') {
1761
            // Lines
1762
            $nbp = 5;
1763
            $xnbp = 0;
1764
            while ($xnbp < $nbp) {
1765
                $line = new FactureLigne($this->db);
1766
                $line->desc = $langs->trans("Description") . " " . $xnbp;
1767
                $line->qty = 1;
1768
                $line->subprice = 100;
1769
                $line->tva_tx = 19.6;
1770
                $line->localtax1_tx = 0;
1771
                $line->localtax2_tx = 0;
1772
                $line->remise_percent = 0;
1773
                if ($xnbp == 1) {        // Qty is negative (product line)
1774
                    $prodid = mt_rand(1, $num_prods);
1775
                    $line->fk_product = $prodids[$prodid];
1776
                    $line->qty = -1;
1777
                    $line->total_ht = -100;
1778
                    $line->total_ttc = -119.6;
1779
                    $line->total_tva = -19.6;
1780
                } elseif ($xnbp == 2) {    // UP is negative (free line)
1781
                    $line->subprice = -100;
1782
                    $line->total_ht = -100;
1783
                    $line->total_ttc = -119.6;
1784
                    $line->total_tva = -19.6;
1785
                    $line->remise_percent = 0;
1786
                } elseif ($xnbp == 3) {    // Discount is 50% (product line)
1787
                    $prodid = mt_rand(1, $num_prods);
1788
                    $line->fk_product = $prodids[$prodid];
1789
                    $line->total_ht = 50;
1790
                    $line->total_ttc = 59.8;
1791
                    $line->total_tva = 9.8;
1792
                    $line->remise_percent = 50;
1793
                } else { // (product line)
1794
                    $prodid = mt_rand(1, $num_prods);
1795
                    $line->fk_product = $prodids[$prodid];
1796
                    $line->total_ht = 100;
1797
                    $line->total_ttc = 119.6;
1798
                    $line->total_tva = 19.6;
1799
                    $line->remise_percent = 0;
1800
                }
1801
1802
                $this->lines[$xnbp] = $line;
1803
                $xnbp++;
1804
1805
                $this->total_ht       += $line->total_ht;
1806
                $this->total_tva      += $line->total_tva;
1807
                $this->total_ttc      += $line->total_ttc;
1808
            }
1809
            $this->revenuestamp = 0;
1810
1811
            // Add a line "offered"
1812
            $line = new FactureLigne($this->db);
1813
            $line->desc = $langs->trans("Description") . " (offered line)";
1814
            $line->qty = 1;
1815
            $line->subprice = 100;
1816
            $line->tva_tx = 19.6;
1817
            $line->localtax1_tx = 0;
1818
            $line->localtax2_tx = 0;
1819
            $line->remise_percent = 100;
1820
            $line->total_ht = 0;
1821
            $line->total_ttc = 0; // 90 * 1.196
1822
            $line->total_tva = 0;
1823
            $prodid = mt_rand(1, $num_prods);
1824
            $line->fk_product = $prodids[$prodid];
1825
1826
            $this->lines[$xnbp] = $line;
1827
            $xnbp++;
1828
        }
1829
1830
        $this->usenewprice = 0;
1831
1832
        return 1;
1833
    }
1834
1835
    /**
1836
     * Function used to replace a thirdparty id with another one.
1837
     *
1838
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
1839
     * @param   int     $origin_id  Old thirdparty id
1840
     * @param   int     $dest_id    New thirdparty id
1841
     * @return  bool
1842
     */
1843
    public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1844
    {
1845
        $tables = array(
1846
            'facture_rec'
1847
        );
1848
1849
        return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1850
    }
1851
1852
    /**
1853
     * Function used to replace a product id with another one.
1854
     *
1855
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
1856
     * @param   int     $origin_id  Old product id
1857
     * @param   int     $dest_id    New product id
1858
     * @return  bool
1859
     */
1860
    public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
1861
    {
1862
        $tables = array(
1863
            'facturedet_rec'
1864
        );
1865
1866
        return CommonObject::commonReplaceProduct($dbs, $origin_id, $dest_id, $tables);
1867
    }
1868
1869
    /**
1870
     *  Update frequency and unit
1871
     *
1872
     *  @param      int     $frequency      value of frequency
1873
     *  @param      string  $unit           unit of frequency  (d, m, y)
1874
     *  @param      int     $notrigger      Disable the trigger
1875
     *  @return     int                     Return integer <0 if KO, >0 if OK
1876
     */
1877
    public function setFrequencyAndUnit($frequency, $unit, $notrigger = 0)
1878
    {
1879
        global $user;
1880
1881
        if (!$this->table_element) {
1882
            dol_syslog(get_class($this) . "::setFrequencyAndUnit was called on object with property table_element not defined", LOG_ERR);
1883
            return -1;
1884
        }
1885
1886
        if (!empty($frequency) && empty($unit)) {
1887
            dol_syslog(get_class($this) . "::setFrequencyAndUnit was called on object with params frequency defined but unit not defined", LOG_ERR);
1888
            return -2;
1889
        }
1890
1891
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1892
        $sql .= ' SET frequency = ' . ($frequency ? $this->db->escape($frequency) : 'null');
1893
        if (!empty($unit)) {
1894
            $sql .= ', unit_frequency = \'' . $this->db->escape($unit) . '\'';
1895
        }
1896
        $sql .= " WHERE rowid = " . ((int) $this->id);
1897
1898
        dol_syslog(get_class($this) . "::setFrequencyAndUnit", LOG_DEBUG);
1899
        if ($this->db->query($sql)) {
1900
            $this->frequency = $frequency;
1901
            if (!empty($unit)) {
1902
                $this->unit_frequency = $unit;
1903
            }
1904
1905
            if (!$notrigger) {
1906
                // Call trigger
1907
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
1908
                if ($result < 0) {
1909
                    return $result;
1910
                }
1911
                // End call triggers
1912
            }
1913
1914
            return 1;
1915
        } else {
1916
            dol_print_error($this->db);
1917
            return -1;
1918
        }
1919
    }
1920
1921
    /**
1922
     *  Update the next date of execution
1923
     *
1924
     *  @param      datetime    $date                   date of execution
1925
     *  @param      int         $increment_nb_gen_done  0 do nothing more, >0 increment nb_gen_done
1926
     *  @param      int         $notrigger              Disable the trigger
1927
     *  @return     int                                 Return integer <0 if KO, >0 if OK
1928
     */
1929
    public function setNextDate($date, $increment_nb_gen_done = 0, $notrigger = 0)
1930
    {
1931
        global $user;
1932
1933
        if (!$this->table_element) {
1934
            dol_syslog(get_class($this) . "::setNextDate was called on object with property table_element not defined", LOG_ERR);
1935
            return -1;
1936
        }
1937
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1938
        $sql .= " SET date_when = " . ($date ? "'" . $this->db->idate($date) . "'" : "null");
1939
        if ($increment_nb_gen_done > 0) {
1940
            $sql .= ', nb_gen_done = nb_gen_done + 1';
1941
        }
1942
        $sql .= " WHERE rowid = " . ((int) $this->id);
1943
1944
        dol_syslog(get_class($this) . "::setNextDate", LOG_DEBUG);
1945
        if ($this->db->query($sql)) {
1946
            $this->date_when = $date;
1947
            if ($increment_nb_gen_done > 0) {
1948
                $this->nb_gen_done++;
1949
            }
1950
1951
            if (!$notrigger) {
1952
                // Call trigger
1953
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
1954
                if ($result < 0) {
1955
                    return $result;
1956
                }
1957
                // End call triggers
1958
            }
1959
            return 1;
1960
        } else {
1961
            dol_print_error($this->db);
1962
            return -1;
1963
        }
1964
    }
1965
1966
    /**
1967
     *  Update the maximum period
1968
     *
1969
     *  @param      int     $nb     number of maximum period
1970
     *  @param      int     $notrigger Disable the trigger
1971
     *  @return     int             Return integer <0 if KO, >0 if OK
1972
     */
1973
    public function setMaxPeriod($nb, $notrigger = 0)
1974
    {
1975
        global $user;
1976
1977
        if (!$this->table_element) {
1978
            dol_syslog(get_class($this) . "::setMaxPeriod was called on object with property table_element not defined", LOG_ERR);
1979
            return -1;
1980
        }
1981
1982
        if (empty($nb)) {
1983
            $nb = 0;
1984
        }
1985
1986
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1987
        $sql .= ' SET nb_gen_max = ' . ((int) $nb);
1988
        $sql .= " WHERE rowid = " . ((int) $this->id);
1989
1990
        dol_syslog(get_class($this) . "::setMaxPeriod", LOG_DEBUG);
1991
        if ($this->db->query($sql)) {
1992
            $this->nb_gen_max = $nb;
1993
1994
            if (!$notrigger) {
1995
                // Call trigger
1996
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
1997
                if ($result < 0) {
1998
                    return $result;
1999
                }
2000
                // End call triggers
2001
            }
2002
2003
            return 1;
2004
        } else {
2005
            dol_print_error($this->db);
2006
            return -1;
2007
        }
2008
    }
2009
2010
    /**
2011
     *  Update the auto validate flag of invoice
2012
     *
2013
     *  @param      int     $validate       0 to create in draft, 1 to create and validate invoice
2014
     *  @param      int     $notrigger      Disable the trigger
2015
     *  @return     int                     Return integer <0 if KO, >0 if OK
2016
     */
2017
    public function setAutoValidate($validate, $notrigger = 0)
2018
    {
2019
        global $user;
2020
2021
        if (!$this->table_element) {
2022
            dol_syslog(get_class($this) . "::setAutoValidate was called on object with property table_element not defined", LOG_ERR);
2023
            return -1;
2024
        }
2025
2026
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
2027
        $sql .= ' SET auto_validate = ' . ((int) $validate);
2028
        $sql .= " WHERE rowid = " . ((int) $this->id);
2029
2030
        dol_syslog(get_class($this) . "::setAutoValidate", LOG_DEBUG);
2031
        if ($this->db->query($sql)) {
2032
            $this->auto_validate = $validate;
2033
2034
            if (!$notrigger) {
2035
                // Call trigger
2036
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
2037
                if ($result < 0) {
2038
                    return $result;
2039
                }
2040
                // End call triggers
2041
            }
2042
2043
            return 1;
2044
        } else {
2045
            dol_print_error($this->db);
2046
            return -1;
2047
        }
2048
    }
2049
2050
    /**
2051
     *  Update the auto generate documents
2052
     *
2053
     *  @param      int     $validate       0 no document, 1 to generate document
2054
     *  @param      int     $notrigger      Disable the trigger
2055
     *  @return     int                     Return integer <0 if KO, >0 if OK
2056
     */
2057
    public function setGeneratePdf($validate, $notrigger = 0)
2058
    {
2059
        global $user;
2060
2061
        if (!$this->table_element) {
2062
            dol_syslog(get_class($this) . "::setGeneratePdf was called on object with property table_element not defined", LOG_ERR);
2063
            return -1;
2064
        }
2065
2066
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
2067
        $sql .= ' SET generate_pdf = ' . ((int) $validate);
2068
        $sql .= " WHERE rowid = " . ((int) $this->id);
2069
2070
        dol_syslog(get_class($this) . "::setGeneratePdf", LOG_DEBUG);
2071
        if ($this->db->query($sql)) {
2072
            $this->generate_pdf = $validate;
2073
2074
            if (!$notrigger) {
2075
                // Call trigger
2076
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
2077
                if ($result < 0) {
2078
                    return $result;
2079
                }
2080
                // End call triggers
2081
            }
2082
2083
            return 1;
2084
        } else {
2085
            dol_print_error($this->db);
2086
            return -1;
2087
        }
2088
    }
2089
2090
    /**
2091
     *  Update the model for documents
2092
     *
2093
     *  @param      string      $model      model of document generator
2094
     *  @param      int     $notrigger      Disable the trigger
2095
     *  @return     int                     Return integer <0 if KO, >0 if OK
2096
     */
2097
    public function setModelPdf($model, $notrigger = 0)
2098
    {
2099
        global $user;
2100
        if (!$this->table_element) {
2101
            dol_syslog(get_class($this) . "::setModelPdf was called on object with property table_element not defined", LOG_ERR);
2102
            return -1;
2103
        }
2104
2105
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
2106
        $sql .= " SET modelpdf = '" . $this->db->escape($model) . "'";
2107
        $sql .= " WHERE rowid = " . ((int) $this->id);
2108
2109
        dol_syslog(get_class($this) . "::setModelPdf", LOG_DEBUG);
2110
        if ($this->db->query($sql)) {
2111
            $this->model_pdf = $model;
2112
2113
            if (!$notrigger) {
2114
                // Call trigger
2115
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
2116
                if ($result < 0) {
2117
                    return $result;
2118
                }
2119
                // End call triggers
2120
            }
2121
2122
            return 1;
2123
        } else {
2124
            dol_print_error($this->db);
2125
            return -1;
2126
        }
2127
    }
2128
}
2129
2130
2131
2132
/**
2133
 *  Class to manage invoice lines of templates.
2134
 *  Saved into database table llx_facturedet_rec
2135
 */
2136
class FactureLigneRec extends CommonInvoiceLine
2137
{
2138
    /**
2139
     * @var string ID to identify managed object
2140
     */
2141
    public $element = 'facturedetrec';
2142
2143
    /**
2144
     * @var string Name of table without prefix where object is stored
2145
     */
2146
    public $table_element = 'facturedet_rec';
2147
2148
    /**
2149
     * @see CommonObjectLine
2150
     */
2151
    public $parent_element = 'facturerec';
2152
2153
    /**
2154
     * @see CommonObjectLine
2155
     */
2156
    public $fk_parent_attribute = 'fk_facture';
2157
2158
    //! From llx_facturedet_rec
2159
    //! Id facture
2160
    public $fk_facture;
2161
    //! Id parent line
2162
    public $fk_parent_line;
2163
2164
    public $fk_product_fournisseur_price;
2165
    public $fk_fournprice; // For backward compatibility
2166
2167
    public $rang;
2168
    //public $situation_percent;    // Not supported on recurring invoice line
2169
2170
    public $desc;
2171
    public $description;
2172
2173
    public $fk_product_type; // Use instead product_type
2174
2175
    public $fk_contract_line;
2176
2177
2178
    /**
2179
     *  Delete line in database
2180
     *
2181
     *  @param      User    $user       Object user
2182
     *  @param      int     $notrigger  Disable triggers
2183
     *  @return     int                 Return integer <0 if KO, >0 if OK
2184
     */
2185
    public function delete(User $user, $notrigger = 0)
2186
    {
2187
        $error = 0;
2188
2189
        $this->db->begin();
2190
2191
        if (!$error) {
2192
            if (!$notrigger) {
2193
                // Call triggers
2194
                $result = $this->call_trigger('LINEBILLREC_DELETE', $user);
2195
                if ($result < 0) {
2196
                    $error++;
2197
                } // Do also here what you must do to rollback action if trigger fail
2198
                // End call triggers
2199
            }
2200
        }
2201
2202
        if (!$error) {
2203
            $result = $this->deleteExtraFields();
2204
            if ($result < 0) {
2205
                $error++;
2206
            }
2207
        }
2208
2209
        if (!$error) {
2210
            $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . ' WHERE rowid=' . ((int) $this->id);
2211
2212
            $res = $this->db->query($sql);
2213
            if (!$res) {
2214
                $error++;
2215
                $this->errors[] = $this->db->lasterror();
2216
            }
2217
        }
2218
2219
        // Commit or rollback
2220
        if ($error) {
2221
            $this->db->rollback();
2222
            return -1;
2223
        } else {
2224
            $this->db->commit();
2225
            return 1;
2226
        }
2227
    }
2228
2229
2230
    /**
2231
     *  Get line of template invoice
2232
     *
2233
     *  @param      int     $rowid      Id of invoice
2234
     *  @return     int                 1 if OK, < 0 if KO
2235
     */
2236
    public function fetch($rowid)
2237
    {
2238
        $sql = 'SELECT l.rowid, l.fk_facture, l.fk_parent_line, l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx,';
2239
        $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
2240
        $sql .= ' l.date_start_fill, l.date_end_fill, l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
2241
        $sql .= ' l.rang, l.special_code,';
2242
        $sql .= ' l.fk_unit, l.fk_contract_line,';
2243
        $sql .= ' l.import_key, l.fk_multicurrency,';
2244
        $sql .= ' l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2245
        $sql .= ' l.buy_price_ht, l.fk_product_fournisseur_price,';
2246
        $sql .= ' l.fk_user_author, l.fk_user_modif,';
2247
        $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
2248
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facturedet_rec as l';
2249
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product as p ON l.fk_product = p.rowid';
2250
        $sql .= ' WHERE l.rowid = ' . ((int) $rowid);
2251
        $sql .= ' ORDER BY l.rang';
2252
2253
        dol_syslog('FactureRec::fetch', LOG_DEBUG);
2254
        $result = $this->db->query($sql);
2255
        if ($result) {
2256
            $objp = $this->db->fetch_object($result);
2257
2258
            $this->id               = $objp->rowid;
2259
            $this->fk_facture       = $objp->fk_facture;
2260
            $this->fk_parent_line   = $objp->fk_parent_line;
2261
            $this->label            = $objp->custom_label; // Label line
2262
            $this->desc             = $objp->description; // Description line
2263
            $this->description      = $objp->description; // Description line
2264
            $this->product_type     = $objp->product_type; // Type of line
2265
            $this->ref              = $objp->product_ref; // Ref product
2266
            $this->product_ref      = $objp->product_ref; // Ref product
2267
            $this->libelle          = $objp->product_label; // deprecated
2268
            $this->product_label = $objp->product_label; // Label product
2269
            $this->product_desc     = $objp->product_desc; // Description product
2270
            $this->fk_product_type  = $objp->fk_product_type; // Type of product
2271
            $this->qty              = $objp->qty;
2272
            $this->price = $objp->price;
2273
            $this->subprice         = $objp->subprice;
2274
            $this->vat_src_code     = $objp->vat_src_code;
2275
            $this->tva_tx           = $objp->tva_tx;
2276
            $this->localtax1_tx     = $objp->localtax1_tx;
2277
            $this->localtax2_tx     = $objp->localtax2_tx;
2278
            $this->localtax1_type   = $objp->localtax1_type;
2279
            $this->localtax2_type   = $objp->localtax2_type;
2280
            $this->remise_percent   = $objp->remise_percent;
2281
            //$this->fk_remise_except = $objp->fk_remise_except;
2282
            $this->fk_product       = $objp->fk_product;
2283
            $this->date_start_fill  = $objp->date_start_fill;
2284
            $this->date_end_fill    = $objp->date_end_fill;
2285
            $this->info_bits        = $objp->info_bits;
2286
            $this->total_ht         = $objp->total_ht;
2287
            $this->total_tva        = $objp->total_tva;
2288
            $this->total_ttc        = $objp->total_ttc;
2289
2290
            $this->rang = $objp->rang;
2291
            $this->special_code = $objp->special_code;
2292
            $this->fk_unit          = $objp->fk_unit;
2293
            $this->fk_contract_line = $objp->fk_contract_line;
2294
            $this->import_key = $objp->import_key;
2295
            $this->fk_multicurrency = $objp->fk_multicurrency;
2296
            $this->multicurrency_code = $objp->multicurrency_code;
2297
            $this->multicurrency_subprice = $objp->multicurrency_subprice;
2298
            $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
2299
            $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
2300
            $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2301
2302
            $this->buy_price_ht = $objp->buy_price_ht;
2303
2304
            $this->fk_product_fournisseur_price = $objp->fk_product_fournisseur_price;
2305
            $this->fk_user_author = $objp->fk_user_author;
0 ignored issues
show
Deprecated Code introduced by
The property CommonInvoiceLine::$fk_user_author has been deprecated: Use user_creation_id ( Ignorable by Annotation )

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

2305
            /** @scrutinizer ignore-deprecated */ $this->fk_user_author = $objp->fk_user_author;

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...
2306
            $this->fk_user_modif = $objp->fk_user_modif;
0 ignored issues
show
Deprecated Code introduced by
The property CommonInvoiceLine::$fk_user_modif has been deprecated: Use user_modification_id ( Ignorable by Annotation )

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

2306
            /** @scrutinizer ignore-deprecated */ $this->fk_user_modif = $objp->fk_user_modif;

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...
2307
2308
            $this->db->free($result);
2309
            return 1;
2310
        } else {
2311
            $this->error = $this->db->lasterror();
2312
            return -3;
2313
        }
2314
    }
2315
2316
2317
    /**
2318
     *  Update a line to invoice_rec.
2319
     *
2320
     *  @param      User    $user                   User
2321
     *  @param      int     $notrigger              No trigger
2322
     *  @return     int                             Return integer <0 if KO, Id of line if OK
2323
     */
2324
    public function update(User $user, $notrigger = 0)
2325
    {
2326
        global $conf;
2327
2328
        $error = 0;
2329
2330
        // Clean parameters
2331
        if (empty($this->fk_parent_line)) {
2332
            $this->fk_parent_line = 0;
2333
        }
2334
2335
        include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php';
2336
2337
        $sql = "UPDATE " . MAIN_DB_PREFIX . "facturedet_rec SET";
2338
        $sql .= " fk_facture = " . ((int) $this->fk_facture);
2339
        $sql .= ", fk_parent_line=" . ($this->fk_parent_line > 0 ? $this->fk_parent_line : "null");
2340
        $sql .= ", label=" . (!empty($this->label) ? "'" . $this->db->escape($this->label) . "'" : "null");
2341
        $sql .= ", description='" . $this->db->escape($this->desc) . "'";
2342
        $sql .= ", price=" . price2num($this->price);
2343
        $sql .= ", qty=" . price2num($this->qty);
2344
        $sql .= ", tva_tx=" . price2num($this->tva_tx);
2345
        $sql .= ", vat_src_code='" . $this->db->escape($this->vat_src_code) . "'";
2346
        $sql .= ", localtax1_tx=" . price2num($this->localtax1_tx);
2347
        $sql .= ", localtax1_type='" . $this->db->escape($this->localtax1_type) . "'";
2348
        $sql .= ", localtax2_tx=" . price2num($this->localtax2_tx);
2349
        $sql .= ", localtax2_type='" . $this->db->escape($this->localtax2_type) . "'";
2350
        $sql .= ", fk_product=" . ($this->fk_product > 0 ? $this->fk_product : "null");
2351
        $sql .= ", product_type=" . ((int) $this->product_type);
2352
        $sql .= ", remise_percent=" . price2num($this->remise_percent);
2353
        $sql .= ", subprice=" . price2num($this->subprice);
2354
        $sql .= ", info_bits=" . price2num($this->info_bits);
2355
        $sql .= ", date_start_fill=" . (int) $this->date_start_fill;
2356
        $sql .= ", date_end_fill=" . (int) $this->date_end_fill;
2357
        if (empty($this->skip_update_total)) {
0 ignored issues
show
Bug Best Practice introduced by
The property skip_update_total does not exist on FactureLigneRec. Since you implemented __get, consider adding a @property annotation.
Loading history...
2358
            $sql .= ", total_ht=" . price2num($this->total_ht);
2359
            $sql .= ", total_tva=" . price2num($this->total_tva);
2360
            $sql .= ", total_localtax1=" . price2num($this->total_localtax1);
2361
            $sql .= ", total_localtax2=" . price2num($this->total_localtax2);
2362
            $sql .= ", total_ttc=" . price2num($this->total_ttc);
2363
        }
2364
        $sql .= ", rang=" . ((int) $this->rang);
2365
        $sql .= ", special_code=" . ((int) $this->special_code);
2366
        $sql .= ", fk_unit=" . ($this->fk_unit ? "'" . $this->db->escape($this->fk_unit) . "'" : "null");
2367
        $sql .= ", fk_contract_line=" . ($this->fk_contract_line ? $this->fk_contract_line : "null");
2368
        $sql .= " WHERE rowid = " . ((int) $this->id);
2369
2370
        $this->db->begin();
2371
2372
        dol_syslog(get_class($this) . "::updateline", LOG_DEBUG);
2373
2374
        $resql = $this->db->query($sql);
2375
        if ($resql) {
2376
            if (!$error) {
2377
                $result = $this->insertExtraFields();
2378
                if ($result < 0) {
2379
                    $error++;
2380
                }
2381
            }
2382
2383
            if (!$error && !$notrigger) {
2384
                // Call trigger
2385
                $result = $this->call_trigger('LINEBILLREC_MODIFY', $user);
2386
                if ($result < 0) {
2387
                    $error++;
2388
                }
2389
                // End call triggers
2390
            }
2391
2392
            if ($error) {
2393
                $this->db->rollback();
2394
                return -2;
2395
            } else {
2396
                $this->db->commit();
2397
                return 1;
2398
            }
2399
        } else {
2400
            $this->error = $this->db->lasterror();
2401
            $this->db->rollback();
2402
            return -2;
2403
        }
2404
    }
2405
}
2406