FactureRec::getLinesArray()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
namespace Dolibarr\Code\Compta\Classes;
30
31
use Dolibarr\Code\Core\Classes\CommonInvoice;
32
use Dolibarr\Code\User\Classes\User;
33
use DoliDB;
34
35
/**
36
 *  \file       htdocs/compta/facture/class/facture-rec.class.php
37
 *  \ingroup    invoice
38
 *  \brief      File of class to manage recurring invoices
39
 */
40
41
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/date.lib.php';
42
43
/**
44
 *  Class to manage invoice templates
45
 * Model FactureRec
46
 */
47
class FactureRec extends CommonInvoice
48
{
49
    const TRIGGER_PREFIX = 'BILLREC';
50
    /**
51
     * @var string ID to identify managed object
52
     */
53
    public $element = 'facturerec';
54
55
    /**
56
     * @var string Name of table without prefix where object is stored
57
     */
58
    public $table_element = 'facture_rec';
59
60
    /**
61
     * @var string    Name of subtable line
62
     */
63
    public $table_element_line = 'facturedet_rec';
64
65
    /**
66
     * @var string Field with ID of parent key if this field has a parent
67
     */
68
    public $fk_element = 'fk_facture';
69
70
    /**
71
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
72
     */
73
    public $picto = 'bill';
74
75
    /**
76
     * @var int Entity
77
     */
78
    public $entity;
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    protected $table_ref_field = 'titre';
84
85
    /**
86
     * @var string The label of recurring invoice
87
     */
88
    public $title;
89
90
    /**
91
     * @var string  The label of recurring invoice
92
     * @deprecated  Use $title instead
93
     */
94
    public $titre;
95
96
    /**
97
     * @var double
98
     */
99
    public $multicurrency_subprice;
100
    public $socid;
101
    public $number;
102
    public $date;
103
    //public $remise;
104
    //public $remise_absolue;
105
    //public $remise_percent;
106
107
    /**
108
     * @deprecated
109
     * @see $total_ht
110
     */
111
    public $total;
112
113
    /**
114
     * @deprecated
115
     * @see $total_tva
116
     */
117
    public $tva;
118
119
    public $date_last_gen;
120
    public $date_when;
121
    public $nb_gen_done;
122
    public $nb_gen_max;
123
124
    public $user_author;
125
126
    /**
127
     * @var int Frequency
128
     */
129
    public $frequency;
130
131
    /**
132
     * @var string Unit frequency
133
     */
134
    public $unit_frequency;
135
136
    public $rang;
137
138
    /**
139
     * @var int special code
140
     */
141
    public $special_code;
142
143
    public $usenewprice = 0;
144
145
    /**
146
     * @var int Deadline for payment
147
     */
148
    public $date_lim_reglement;
149
    public $cond_reglement_code; // Code in llx_c_paiement
150
    public $mode_reglement_code; // Code in llx_c_paiement
151
152
    public $suspended; // status
153
154
    public $auto_validate; // 0 to create in draft, 1 to create and validate the new invoice
155
    public $generate_pdf; // 1 to generate PDF on invoice generation (default)
156
157
158
    /**
159
     *  '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')
160
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
161
     *  'label' the translation key.
162
     *  'enabled' is a condition when the field must be managed.
163
     *  'position' is the sort order of field.
164
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
165
     *  '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)
166
     *  'noteditable' says if field is not editable (1 or 0)
167
     *  '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.
168
     *  'index' if we want an index in database.
169
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
170
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
171
     *  '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).
172
     *  'css' is the CSS style to use on field. For example: 'maxwidth200'
173
     *  'help' is a string visible as a tooltip on field
174
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
175
     *  '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.
176
     *  'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
177
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
178
     *
179
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
180
     */
181
182
    // BEGIN MODULEBUILDER PROPERTIES
183
    /**
184
     * @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...
185
     */
186
    public $fields = array(
187
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
188
        'titre' => array('type' => 'varchar(100)', 'label' => 'Titre', 'enabled' => 1, 'showoncombobox' => 1, 'visible' => -1, 'position' => 15),
189
        'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 20, 'index' => 1),
190
        'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 25),
191
        'subtype' => array('type' => 'smallint(6)', 'label' => 'InvoiceSubtype', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 30),
192
        'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 35),
193
        'total_tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 55, 'isameasure' => 1),
194
        'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 60, 'isameasure' => 1),
195
        'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 65, 'isameasure' => 1),
196
        'total_ht' => array('type' => 'double(24,8)', 'label' => 'Total', 'enabled' => 1, 'visible' => -1, 'position' => 70, 'isameasure' => 1),
197
        'total_ttc' => array('type' => 'double(24,8)', 'label' => 'Total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 75, 'isameasure' => 1),
198
        'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fk user author', 'enabled' => 1, 'visible' => -1, 'position' => 80),
199
        '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),
200
        'fk_cond_reglement' => array('type' => 'integer', 'label' => 'Fk cond reglement', 'enabled' => 1, 'visible' => -1, 'position' => 90),
201
        'fk_mode_reglement' => array('type' => 'integer', 'label' => 'Fk mode reglement', 'enabled' => 1, 'visible' => -1, 'position' => 95),
202
        'date_lim_reglement' => array('type' => 'date', 'label' => 'Date lim reglement', 'enabled' => 1, 'visible' => -1, 'position' => 100),
203
        'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 105),
204
        'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 110),
205
        'modelpdf' => array('type' => 'varchar(255)', 'label' => 'Modelpdf', 'enabled' => 1, 'visible' => -1, 'position' => 115),
206
        'date_when' => array('type' => 'datetime', 'label' => 'Date when', 'enabled' => 1, 'visible' => -1, 'position' => 130),
207
        'date_last_gen' => array('type' => 'datetime', 'label' => 'Date last gen', 'enabled' => 1, 'visible' => -1, 'position' => 135),
208
        'nb_gen_done' => array('type' => 'integer', 'label' => 'Nb gen done', 'enabled' => 1, 'visible' => -1, 'position' => 140),
209
        'nb_gen_max' => array('type' => 'integer', 'label' => 'Nb gen max', 'enabled' => 1, 'visible' => -1, 'position' => 145),
210
        'frequency' => array('type' => 'integer', 'label' => 'Frequency', 'enabled' => 1, 'visible' => -1, 'position' => 150),
211
        'unit_frequency' => array('type' => 'varchar(2)', 'label' => 'UnitFrequency', 'enabled' => 1, 'visible' => -1, 'position' => 152),
212
        'usenewprice' => array('type' => 'integer', 'label' => 'UseNewPrice', 'enabled' => 1, 'visible' => 0, 'position' => 155),
213
        'revenuestamp' => array('type' => 'double(24,8)', 'label' => 'RevenueStamp', 'enabled' => 1, 'visible' => -1, 'position' => 160, 'isameasure' => 1),
214
        'auto_validate' => array('type' => 'integer', 'label' => 'Auto validate', 'enabled' => 1, 'visible' => -1, 'position' => 165),
215
        'generate_pdf' => array('type' => 'integer', 'label' => 'Generate pdf', 'enabled' => 1, 'visible' => -1, 'position' => 170),
216
        'fk_account' => array('type' => 'integer', 'label' => 'Fk account', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 175),
217
        'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 1, 'visible' => -1, 'position' => 180),
218
        'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrency code', 'enabled' => 1, 'visible' => -1, 'position' => 185),
219
        'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrency tx', 'enabled' => 1, 'visible' => -1, 'position' => 190, 'isameasure' => 1),
220
        'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ht', 'enabled' => 1, 'visible' => -1, 'position' => 195, 'isameasure' => 1),
221
        'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total tva', 'enabled' => 1, 'visible' => -1, 'position' => 200, 'isameasure' => 1),
222
        'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 205, 'isameasure' => 1),
223
        'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 210),
224
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 215),
225
        'suspended' => array('type' => 'integer', 'label' => 'Suspended', 'enabled' => 1, 'visible' => -1, 'position' => 225),
226
    );
227
    // END MODULEBUILDER PROPERTIES
228
229
    const STATUS_NOTSUSPENDED = 0;
230
    const STATUS_SUSPENDED = 1;
231
232
233
234
    /**
235
     *  Constructor
236
     *
237
     *  @param      DoliDB      $db     Database handler
238
     */
239
    public function __construct(DoliDB $db)
240
    {
241
        $this->db = $db;
242
    }
243
244
    /**
245
     *  Create a predefined invoice
246
     *
247
     *  @param      User    $user       User object
248
     *  @param      int     $facid      Id of source invoice
249
     *  @param      int     $notrigger  No trigger
250
     *  @param      array   $onlylines  Only the lines of the array
251
     *  @return     int                 Return integer <0 if KO, id of invoice created if OK
252
     */
253
    public function create($user, $facid, $notrigger = 0, $onlylines = array())
254
    {
255
        global $conf;
256
257
        $error = 0;
258
        $now = dol_now();
259
260
        // Clean parameters
261
        $this->titre = trim(isset($this->titre) ? $this->titre : $this->title); // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Compta\Classes\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

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

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

599
                /** @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...
600
                $this->title                  = $obj->title;
601
                $this->ref                    = $obj->title;
602
                $this->subtype                = $obj->subtype;
603
                $this->suspended              = $obj->suspended;
604
                $this->total_ht               = $obj->total_ht;
605
                $this->total_tva              = $obj->total_tva;
606
                $this->total_localtax1        = $obj->localtax1;
607
                $this->total_localtax2        = $obj->localtax2;
608
                $this->total_ttc              = $obj->total_ttc;
609
                $this->socid                  = $obj->fk_soc;
610
                $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...
611
                $this->mode_reglement_id      = $obj->fk_mode_reglement;
612
                $this->mode_reglement_code    = $obj->mode_reglement_code;
613
                $this->mode_reglement         = $obj->mode_reglement_libelle;
614
                $this->cond_reglement_id      = $obj->fk_cond_reglement;
615
                $this->cond_reglement_code    = $obj->cond_reglement_code;
616
                $this->cond_reglement         = $obj->cond_reglement_libelle;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\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

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

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

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

1758
        /** @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...
1759
        $this->fk_incoterms = 0;
1760
        $this->location_incoterms = '';
1761
1762
        if (empty($option) || $option != 'nolines') {
1763
            // Lines
1764
            $nbp = 5;
1765
            $xnbp = 0;
1766
            while ($xnbp < $nbp) {
1767
                $line = new FactureLigne($this->db);
1768
                $line->desc = $langs->trans("Description") . " " . $xnbp;
1769
                $line->qty = 1;
1770
                $line->subprice = 100;
1771
                $line->tva_tx = 19.6;
1772
                $line->localtax1_tx = 0;
1773
                $line->localtax2_tx = 0;
1774
                $line->remise_percent = 0;
1775
                if ($xnbp == 1) {        // Qty is negative (product line)
1776
                    $prodid = mt_rand(1, $num_prods);
1777
                    $line->fk_product = $prodids[$prodid];
1778
                    $line->qty = -1;
1779
                    $line->total_ht = -100;
1780
                    $line->total_ttc = -119.6;
1781
                    $line->total_tva = -19.6;
1782
                } elseif ($xnbp == 2) {    // UP is negative (free line)
1783
                    $line->subprice = -100;
1784
                    $line->total_ht = -100;
1785
                    $line->total_ttc = -119.6;
1786
                    $line->total_tva = -19.6;
1787
                    $line->remise_percent = 0;
1788
                } elseif ($xnbp == 3) {    // Discount is 50% (product line)
1789
                    $prodid = mt_rand(1, $num_prods);
1790
                    $line->fk_product = $prodids[$prodid];
1791
                    $line->total_ht = 50;
1792
                    $line->total_ttc = 59.8;
1793
                    $line->total_tva = 9.8;
1794
                    $line->remise_percent = 50;
1795
                } else { // (product line)
1796
                    $prodid = mt_rand(1, $num_prods);
1797
                    $line->fk_product = $prodids[$prodid];
1798
                    $line->total_ht = 100;
1799
                    $line->total_ttc = 119.6;
1800
                    $line->total_tva = 19.6;
1801
                    $line->remise_percent = 0;
1802
                }
1803
1804
                $this->lines[$xnbp] = $line;
1805
                $xnbp++;
1806
1807
                $this->total_ht       += $line->total_ht;
1808
                $this->total_tva      += $line->total_tva;
1809
                $this->total_ttc      += $line->total_ttc;
1810
            }
1811
            $this->revenuestamp = 0;
1812
1813
            // Add a line "offered"
1814
            $line = new FactureLigne($this->db);
1815
            $line->desc = $langs->trans("Description") . " (offered line)";
1816
            $line->qty = 1;
1817
            $line->subprice = 100;
1818
            $line->tva_tx = 19.6;
1819
            $line->localtax1_tx = 0;
1820
            $line->localtax2_tx = 0;
1821
            $line->remise_percent = 100;
1822
            $line->total_ht = 0;
1823
            $line->total_ttc = 0; // 90 * 1.196
1824
            $line->total_tva = 0;
1825
            $prodid = mt_rand(1, $num_prods);
1826
            $line->fk_product = $prodids[$prodid];
1827
1828
            $this->lines[$xnbp] = $line;
1829
            $xnbp++;
1830
        }
1831
1832
        $this->usenewprice = 0;
1833
1834
        return 1;
1835
    }
1836
1837
    /**
1838
     * Function used to replace a thirdparty id with another one.
1839
     *
1840
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
1841
     * @param   int     $origin_id  Old thirdparty id
1842
     * @param   int     $dest_id    New thirdparty id
1843
     * @return  bool
1844
     */
1845
    public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1846
    {
1847
        $tables = array(
1848
            'facture_rec'
1849
        );
1850
1851
        return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1852
    }
1853
1854
    /**
1855
     * Function used to replace a product id with another one.
1856
     *
1857
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
1858
     * @param   int     $origin_id  Old product id
1859
     * @param   int     $dest_id    New product id
1860
     * @return  bool
1861
     */
1862
    public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
1863
    {
1864
        $tables = array(
1865
            'facturedet_rec'
1866
        );
1867
1868
        return CommonObject::commonReplaceProduct($dbs, $origin_id, $dest_id, $tables);
1869
    }
1870
1871
    /**
1872
     *  Update frequency and unit
1873
     *
1874
     *  @param      int     $frequency      value of frequency
1875
     *  @param      string  $unit           unit of frequency  (d, m, y)
1876
     *  @param      int     $notrigger      Disable the trigger
1877
     *  @return     int                     Return integer <0 if KO, >0 if OK
1878
     */
1879
    public function setFrequencyAndUnit($frequency, $unit, $notrigger = 0)
1880
    {
1881
        global $user;
1882
1883
        if (!$this->table_element) {
1884
            dol_syslog(get_only_class($this) . "::setFrequencyAndUnit was called on object with property table_element not defined", LOG_ERR);
1885
            return -1;
1886
        }
1887
1888
        if (!empty($frequency) && empty($unit)) {
1889
            dol_syslog(get_only_class($this) . "::setFrequencyAndUnit was called on object with params frequency defined but unit not defined", LOG_ERR);
1890
            return -2;
1891
        }
1892
1893
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1894
        $sql .= ' SET frequency = ' . ($frequency ? $this->db->escape($frequency) : 'null');
1895
        if (!empty($unit)) {
1896
            $sql .= ', unit_frequency = \'' . $this->db->escape($unit) . '\'';
1897
        }
1898
        $sql .= " WHERE rowid = " . ((int) $this->id);
1899
1900
        dol_syslog(get_only_class($this) . "::setFrequencyAndUnit", LOG_DEBUG);
1901
        if ($this->db->query($sql)) {
1902
            $this->frequency = $frequency;
1903
            if (!empty($unit)) {
1904
                $this->unit_frequency = $unit;
1905
            }
1906
1907
            if (!$notrigger) {
1908
                // Call trigger
1909
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
1910
                if ($result < 0) {
1911
                    return $result;
1912
                }
1913
                // End call triggers
1914
            }
1915
1916
            return 1;
1917
        } else {
1918
            dol_print_error($this->db);
1919
            return -1;
1920
        }
1921
    }
1922
1923
    /**
1924
     *  Update the next date of execution
1925
     *
1926
     *  @param      datetime    $date                   date of execution
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Compta\Classes\datetime was not found. Did you mean datetime? If so, make sure to prefix the type with \.
Loading history...
1927
     *  @param      int         $increment_nb_gen_done  0 do nothing more, >0 increment nb_gen_done
1928
     *  @param      int         $notrigger              Disable the trigger
1929
     *  @return     int                                 Return integer <0 if KO, >0 if OK
1930
     */
1931
    public function setNextDate($date, $increment_nb_gen_done = 0, $notrigger = 0)
1932
    {
1933
        global $user;
1934
1935
        if (!$this->table_element) {
1936
            dol_syslog(get_only_class($this) . "::setNextDate was called on object with property table_element not defined", LOG_ERR);
1937
            return -1;
1938
        }
1939
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1940
        $sql .= " SET date_when = " . ($date ? "'" . $this->db->idate($date) . "'" : "null");
1941
        if ($increment_nb_gen_done > 0) {
1942
            $sql .= ', nb_gen_done = nb_gen_done + 1';
1943
        }
1944
        $sql .= " WHERE rowid = " . ((int) $this->id);
1945
1946
        dol_syslog(get_only_class($this) . "::setNextDate", LOG_DEBUG);
1947
        if ($this->db->query($sql)) {
1948
            $this->date_when = $date;
1949
            if ($increment_nb_gen_done > 0) {
1950
                $this->nb_gen_done++;
1951
            }
1952
1953
            if (!$notrigger) {
1954
                // Call trigger
1955
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
1956
                if ($result < 0) {
1957
                    return $result;
1958
                }
1959
                // End call triggers
1960
            }
1961
            return 1;
1962
        } else {
1963
            dol_print_error($this->db);
1964
            return -1;
1965
        }
1966
    }
1967
1968
    /**
1969
     *  Update the maximum period
1970
     *
1971
     *  @param      int     $nb     number of maximum period
1972
     *  @param      int     $notrigger Disable the trigger
1973
     *  @return     int             Return integer <0 if KO, >0 if OK
1974
     */
1975
    public function setMaxPeriod($nb, $notrigger = 0)
1976
    {
1977
        global $user;
1978
1979
        if (!$this->table_element) {
1980
            dol_syslog(get_only_class($this) . "::setMaxPeriod was called on object with property table_element not defined", LOG_ERR);
1981
            return -1;
1982
        }
1983
1984
        if (empty($nb)) {
1985
            $nb = 0;
1986
        }
1987
1988
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1989
        $sql .= ' SET nb_gen_max = ' . ((int) $nb);
1990
        $sql .= " WHERE rowid = " . ((int) $this->id);
1991
1992
        dol_syslog(get_only_class($this) . "::setMaxPeriod", LOG_DEBUG);
1993
        if ($this->db->query($sql)) {
1994
            $this->nb_gen_max = $nb;
1995
1996
            if (!$notrigger) {
1997
                // Call trigger
1998
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
1999
                if ($result < 0) {
2000
                    return $result;
2001
                }
2002
                // End call triggers
2003
            }
2004
2005
            return 1;
2006
        } else {
2007
            dol_print_error($this->db);
2008
            return -1;
2009
        }
2010
    }
2011
2012
    /**
2013
     *  Update the auto validate flag of invoice
2014
     *
2015
     *  @param      int     $validate       0 to create in draft, 1 to create and validate invoice
2016
     *  @param      int     $notrigger      Disable the trigger
2017
     *  @return     int                     Return integer <0 if KO, >0 if OK
2018
     */
2019
    public function setAutoValidate($validate, $notrigger = 0)
2020
    {
2021
        global $user;
2022
2023
        if (!$this->table_element) {
2024
            dol_syslog(get_only_class($this) . "::setAutoValidate was called on object with property table_element not defined", LOG_ERR);
2025
            return -1;
2026
        }
2027
2028
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
2029
        $sql .= ' SET auto_validate = ' . ((int) $validate);
2030
        $sql .= " WHERE rowid = " . ((int) $this->id);
2031
2032
        dol_syslog(get_only_class($this) . "::setAutoValidate", LOG_DEBUG);
2033
        if ($this->db->query($sql)) {
2034
            $this->auto_validate = $validate;
2035
2036
            if (!$notrigger) {
2037
                // Call trigger
2038
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
2039
                if ($result < 0) {
2040
                    return $result;
2041
                }
2042
                // End call triggers
2043
            }
2044
2045
            return 1;
2046
        } else {
2047
            dol_print_error($this->db);
2048
            return -1;
2049
        }
2050
    }
2051
2052
    /**
2053
     *  Update the auto generate documents
2054
     *
2055
     *  @param      int     $validate       0 no document, 1 to generate document
2056
     *  @param      int     $notrigger      Disable the trigger
2057
     *  @return     int                     Return integer <0 if KO, >0 if OK
2058
     */
2059
    public function setGeneratePdf($validate, $notrigger = 0)
2060
    {
2061
        global $user;
2062
2063
        if (!$this->table_element) {
2064
            dol_syslog(get_only_class($this) . "::setGeneratePdf was called on object with property table_element not defined", LOG_ERR);
2065
            return -1;
2066
        }
2067
2068
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
2069
        $sql .= ' SET generate_pdf = ' . ((int) $validate);
2070
        $sql .= " WHERE rowid = " . ((int) $this->id);
2071
2072
        dol_syslog(get_only_class($this) . "::setGeneratePdf", LOG_DEBUG);
2073
        if ($this->db->query($sql)) {
2074
            $this->generate_pdf = $validate;
2075
2076
            if (!$notrigger) {
2077
                // Call trigger
2078
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
2079
                if ($result < 0) {
2080
                    return $result;
2081
                }
2082
                // End call triggers
2083
            }
2084
2085
            return 1;
2086
        } else {
2087
            dol_print_error($this->db);
2088
            return -1;
2089
        }
2090
    }
2091
2092
    /**
2093
     *  Update the model for documents
2094
     *
2095
     *  @param      string      $model      model of document generator
2096
     *  @param      int     $notrigger      Disable the trigger
2097
     *  @return     int                     Return integer <0 if KO, >0 if OK
2098
     */
2099
    public function setModelPdf($model, $notrigger = 0)
2100
    {
2101
        global $user;
2102
        if (!$this->table_element) {
2103
            dol_syslog(get_only_class($this) . "::setModelPdf was called on object with property table_element not defined", LOG_ERR);
2104
            return -1;
2105
        }
2106
2107
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
2108
        $sql .= " SET modelpdf = '" . $this->db->escape($model) . "'";
2109
        $sql .= " WHERE rowid = " . ((int) $this->id);
2110
2111
        dol_syslog(get_only_class($this) . "::setModelPdf", LOG_DEBUG);
2112
        if ($this->db->query($sql)) {
2113
            $this->model_pdf = $model;
2114
2115
            if (!$notrigger) {
2116
                // Call trigger
2117
                $result = $this->call_trigger('BILLREC_MODIFY', $user);
2118
                if ($result < 0) {
2119
                    return $result;
2120
                }
2121
                // End call triggers
2122
            }
2123
2124
            return 1;
2125
        } else {
2126
            dol_print_error($this->db);
2127
            return -1;
2128
        }
2129
    }
2130
}
2131