Passed
Push — EXTRACT_CLASSES ( 231cec )
by Rafael
70:48
created

BookKeeping::createStd()   F

Complexity

Conditions 47
Paths > 20000

Size

Total Lines 158
Code Lines 115

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 47
eloc 115
nc 786432
nop 3
dl 0
loc 158
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2014-2017  Olivier Geffroy             <[email protected]>
4
 * Copyright (C) 2015-2022  Alexandre Spangaro          <[email protected]>
5
 * Copyright (C) 2015-2020  Florian Henry               <[email protected]>
6
 * Copyright (C) 2018-2024  Frédéric France             <[email protected]>
7
 * Copyright (C) 2024		MDW							<[email protected]>
8
 * Copyright (C) 2024       Rafael San José             <[email protected]>
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23
24
namespace Dolibarr\Code\Accountancy\Classes;
25
26
use Dolibarr\Code\Accountancy\Classes\AccountingAccount;
27
use Dolibarr\Code\Accountancy\Classes\AccountingJournal;
28
use Dolibarr\Code\Accountancy\Classes\BookKeepingLine;
29
use Dolibarr\Core\Base\CommonObject;
30
use Dolibarr\Core\Base\CommonObjectLine;
31
use DoliDB;
32
33
/**
34
 * \file        htdocs/accountancy/class/bookkeeping.class.php
35
 * \ingroup     Accountancy (Double entries)
36
 * \brief       File of class to manage Ledger (General Ledger and Subledger)
37
 */
38
39
// Class
40
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/fiscalyear.class.php';
41
42
/**
43
 * Class to manage Ledger (General Ledger and Subledger)
44
 */
45
class BookKeeping extends CommonObject
46
{
47
    /**
48
     * @var string Id to identify managed objects
49
     */
50
    public $element = 'accountingbookkeeping';
51
52
    /**
53
     * @var string Name of table without prefix where object is stored
54
     */
55
    public $table_element = 'accounting_bookkeeping';
56
57
    /**
58
     * @var int Entity
59
     */
60
    public $entity;
61
62
    /**
63
     * @var BookKeepingLine[] Lines
64
     */
65
    public $lines = array();
66
67
    /**
68
     * @var int ID
69
     */
70
    public $id;
71
72
    /**
73
     * @var int Date of source document, in db date NOT NULL
74
     */
75
    public $doc_date;
76
77
    /**
78
     * @var int Deadline for payment
79
     */
80
    public $date_lim_reglement;
81
82
    /**
83
     * @var string doc_type
84
     */
85
    public $doc_type;
86
87
    /**
88
     * @var string doc_ref
89
     */
90
    public $doc_ref;
91
92
    /**
93
     * @var int ID
94
     */
95
    public $fk_doc;
96
97
    /**
98
     * @var int ID
99
     */
100
    public $fk_docdet;
101
102
    /**
103
     * @var string thirdparty code
104
     */
105
    public $thirdparty_code;
106
107
    /**
108
     * @var string subledger account
109
     */
110
    public $subledger_account;
111
112
    /**
113
     * @var string subledger label
114
     */
115
    public $subledger_label;
116
117
    /**
118
     * @var string  doc_type
119
     */
120
    public $numero_compte;
121
122
    /**
123
     * @var string label compte
124
     */
125
    public $label_compte;
126
127
    /**
128
     * @var string label operation
129
     */
130
    public $label_operation;
131
132
    /**
133
     * @var float FEC:Debit
134
     */
135
    public $debit;
136
137
    /**
138
     * @var float FEC:Credit
139
     */
140
    public $credit;
141
142
    /**
143
     * @var float FEC:Amount (Not necessary)
144
     * @deprecated No more used (we have info into debit/credit and sens)
145
     */
146
    public $montant;
147
148
    /**
149
     * @var float FEC:Amount (Not necessary)
150
     * @deprecated No more used (we have info into debit/credit and sens)
151
     */
152
    public $amount;
153
154
    /**
155
     * @var string FEC:Sens (Not necessary)
156
     */
157
    public $sens;
158
159
    /**
160
     * @var int ID
161
     */
162
    public $fk_user_author;
163
164
    /**
165
     * @var string key for import
166
     */
167
    public $import_key;
168
169
    /**
170
     * @var string code journal
171
     */
172
    public $code_journal;
173
174
    /**
175
     * @var string label journal
176
     */
177
    public $journal_label;
178
179
    /**
180
     * @var int accounting transaction id
181
     */
182
    public $piece_num;
183
184
    /**
185
     * @var BookKeepingLine[] Movement line array
186
     */
187
    public $linesmvt = array();
188
189
    /**
190
     * @var BookKeepingLine[] export line array
191
     */
192
    public $linesexport = array();
193
194
    /**
195
     * @var integer|string date of movement validated & lock
196
     */
197
    public $date_validation;
198
199
    /**
200
     * @var integer|string date of movement who are noticed like exported
201
     */
202
    public $date_export;
203
204
    /**
205
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
206
     */
207
    public $picto = 'generic';
208
209
    /**
210
     * @var string[]    SQL filter used for check if the bookkeeping record can be created/inserted/modified/deleted (cached)
211
     */
212
    public static $can_modify_bookkeeping_sql_cached;
213
214
215
    /**
216
     * Constructor
217
     *
218
     * @param DoliDB $db Database handler
219
     */
220
    public function __construct(DoliDB $db)
221
    {
222
        $this->db = $db;
0 ignored issues
show
Documentation Bug introduced by
It seems like $db of type DoliDB is incompatible with the declared type Dolibarr\Core\Base\DoliDB of property $db.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
223
    }
224
225
    /**
226
     * Create object into database
227
     *
228
     * @param  User $user       User that creates
229
     * @param  int  $notrigger  false=launch triggers after, true=disable triggers
230
     * @return int              Return integer <0 if KO, Id of created object if OK
231
     */
232
    public function create(User $user, $notrigger = 0)
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\User was not found. Did you mean User? If so, make sure to prefix the type with \.
Loading history...
233
    {
234
        global $conf, $langs;
235
236
        dol_syslog(__METHOD__, LOG_DEBUG);
237
238
        $error = 0;
239
240
        // Clean parameters</center>
241
        if (isset($this->doc_type)) {
242
            $this->doc_type = trim($this->doc_type);
243
        }
244
        if (isset($this->doc_ref)) {
245
            $this->doc_ref = trim($this->doc_ref);
246
        }
247
        if (isset($this->fk_doc)) {
248
            $this->fk_doc = (int) $this->fk_doc;
249
        }
250
        if (isset($this->fk_docdet)) {
251
            $this->fk_docdet = (int) $this->fk_docdet;
252
        }
253
        if (isset($this->thirdparty_code)) {
254
            $this->thirdparty_code = trim($this->thirdparty_code);
255
        }
256
        if (isset($this->subledger_account)) {
257
            $this->subledger_account = trim($this->subledger_account);
258
        }
259
        if (isset($this->subledger_label)) {
260
            $this->subledger_label = trim($this->subledger_label);
261
        }
262
        if (isset($this->numero_compte)) {
263
            $this->numero_compte = trim($this->numero_compte);
264
        }
265
        if (isset($this->label_compte)) {
266
            $this->label_compte = trim($this->label_compte);
267
        }
268
        if (isset($this->label_operation)) {
269
            $this->label_operation = trim($this->label_operation);
270
        }
271
        if (isset($this->debit)) {
272
            $this->debit = (float) $this->debit;
273
        }
274
        if (isset($this->credit)) {
275
            $this->credit = (float) $this->credit;
276
        }
277
        if (isset($this->montant)) {
278
            $this->montant = (float) $this->montant;
279
        }
280
        if (isset($this->amount)) {
281
            $this->amount = (float) $this->amount;
282
        }
283
        if (isset($this->sens)) {
284
            $this->sens = trim($this->sens);
285
        }
286
        if (isset($this->import_key)) {
287
            $this->import_key = trim($this->import_key);
288
        }
289
        if (isset($this->code_journal)) {
290
            $this->code_journal = trim($this->code_journal);
291
        }
292
        if (isset($this->journal_label)) {
293
            $this->journal_label = trim($this->journal_label);
294
        }
295
        if (isset($this->piece_num)) {
296
            $this->piece_num = (int) $this->piece_num;
297
        }
298
        if (empty($this->debit)) {
299
            $this->debit = 0.0;
300
        }
301
        if (empty($this->credit)) {
302
            $this->credit = 0.0;
303
        }
304
305
        $result = $this->validBookkeepingDate($this->doc_date);
306
        if ($result < 0) {
307
            return -1;
308
        } elseif ($result == 0) {
309
            if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
310
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
311
            } else {
312
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
313
            }
314
            return -1;
315
        }
316
317
        // Check parameters
318
        if (($this->numero_compte == "") || $this->numero_compte == '-1' || $this->numero_compte == 'NotDefined') {
319
            $langs->loadLangs(array("errors"));
320
            if (in_array($this->doc_type, array('bank', 'expense_report'))) {
321
                $this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForBankLine', $this->fk_docdet, $this->doc_type);
322
            } else {
323
                //$this->errors[]=$langs->trans('ErrorFieldAccountNotDefinedForInvoiceLine', $this->doc_ref,  $this->label_compte);
324
                $mesg = $this->doc_ref . ', ' . $langs->trans("AccountAccounting") . ': ' . ($this->numero_compte != -1 ? $this->numero_compte : $langs->trans("Unknown"));
325
                if ($this->subledger_account && $this->subledger_account != $this->numero_compte) {
326
                    $mesg .= ', ' . $langs->trans("SubledgerAccount") . ': ' . $this->subledger_account;
327
                }
328
                $this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForLine', $mesg);
329
            }
330
331
            return -1;
332
        }
333
334
        $this->db->begin();
335
336
        $this->piece_num = 0;
337
338
        // First check if line not yet already in bookkeeping.
339
        // Note that we must include 'doc_type - fk_doc - numero_compte - label' to be sure to have unicity of line (because we may have several lines
340
        // with same doc_type, fk_doc, numero_compte for 1 invoice line when using localtaxes with same account)
341
        // WARNING: This is not reliable, label may have been modified. This is just a small protection.
342
        // The page that make transfer make the test on couple (doc_type - fk_doc) only.
343
        $sql = "SELECT count(*) as nb";
344
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
345
        $sql .= " WHERE doc_type = '" . $this->db->escape($this->doc_type) . "'";
346
        $sql .= " AND fk_doc = " . ((int) $this->fk_doc);
347
        if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) {
348
            // DO NOT USE THIS IN PRODUCTION. This will generate a lot of trouble into reports and will corrupt database (by generating duplicate entries.
349
            $sql .= " AND fk_docdet = " . ((int) $this->fk_docdet); // This field can be 0 if record is for several lines
350
        }
351
        $sql .= " AND numero_compte = '" . $this->db->escape($this->numero_compte) . "'";
352
        $sql .= " AND label_operation = '" . $this->db->escape($this->label_operation) . "'";
353
        $sql .= " AND entity = " . $conf->entity; // Do not use getEntity for accounting features
354
355
        $resql = $this->db->query($sql);
356
357
        if ($resql) {
358
            $row = $this->db->fetch_object($resql);
359
            if ($row->nb == 0) {    // Not already into bookkeeping
360
                // Check to know if piece_num already exists for data we try to insert to reuse the same value
361
                $sqlnum = "SELECT piece_num";
362
                $sqlnum .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
363
                $sqlnum .= " WHERE doc_type = '" . $this->db->escape($this->doc_type) . "'"; // For example doc_type = 'bank'
364
                $sqlnum .= " AND fk_doc = " . ((int) $this->fk_doc);
365
                if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) {
366
                    // fk_docdet is rowid into llx_bank or llx_facturedet or llx_facturefourndet, or ...
367
                    $sqlnum .= " AND fk_docdet = " . ((int) $this->fk_docdet);
368
                }
369
                $sqlnum .= " AND doc_ref = '" . $this->db->escape($this->doc_ref) . "'"; // ref of source object
370
                $sqlnum .= " AND entity = " . $conf->entity; // Do not use getEntity for accounting features
371
372
                dol_syslog(get_class($this) . ":: create sqlnum=" . $sqlnum, LOG_DEBUG);
373
                $resqlnum = $this->db->query($sqlnum);
374
                if ($resqlnum) {
375
                    $objnum = $this->db->fetch_object($resqlnum);
376
                    $this->piece_num = $objnum->piece_num;
377
                }
378
379
                dol_syslog(get_class($this) . "::create this->piece_num=" . $this->piece_num, LOG_DEBUG);
380
                if (empty($this->piece_num)) {
381
                    $sqlnum = "SELECT MAX(piece_num)+1 as maxpiecenum";
382
                    $sqlnum .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
383
                    $sqlnum .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
384
385
                    $resqlnum = $this->db->query($sqlnum);
386
                    if ($resqlnum) {
387
                        $objnum = $this->db->fetch_object($resqlnum);
388
                        $this->piece_num = $objnum->maxpiecenum;
389
                    }
390
                    dol_syslog(get_class($this) . ":: create now this->piece_num=" . $this->piece_num, LOG_DEBUG);
391
                }
392
                if (empty($this->piece_num)) {
393
                    $this->piece_num = 1;
394
                }
395
396
                $now = dol_now();
397
398
                $sql = "INSERT INTO " . MAIN_DB_PREFIX . $this->table_element . " (";
399
                $sql .= "doc_date";
400
                $sql .= ", date_lim_reglement";
401
                $sql .= ", doc_type";
402
                $sql .= ", doc_ref";
403
                $sql .= ", fk_doc";
404
                $sql .= ", fk_docdet";
405
                $sql .= ", thirdparty_code";
406
                $sql .= ", subledger_account";
407
                $sql .= ", subledger_label";
408
                $sql .= ", numero_compte";
409
                $sql .= ", label_compte";
410
                $sql .= ", label_operation";
411
                $sql .= ", debit";
412
                $sql .= ", credit";
413
                $sql .= ", montant";
414
                $sql .= ", sens";
415
                $sql .= ", fk_user_author";
416
                $sql .= ", date_creation";
417
                $sql .= ", code_journal";
418
                $sql .= ", journal_label";
419
                $sql .= ", piece_num";
420
                $sql .= ', entity';
421
                $sql .= ") VALUES (";
422
                $sql .= "'" . $this->db->idate($this->doc_date) . "'";
423
                $sql .= ", " . (!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'" . $this->db->idate($this->date_lim_reglement) . "'");
424
                $sql .= ", '" . $this->db->escape($this->doc_type) . "'";
425
                $sql .= ", '" . $this->db->escape($this->doc_ref) . "'";
426
                $sql .= ", " . ((int) $this->fk_doc);
427
                $sql .= ", " . ((int) $this->fk_docdet);
428
                $sql .= ", " . (!empty($this->thirdparty_code) ? ("'" . $this->db->escape($this->thirdparty_code) . "'") : "NULL");
429
                $sql .= ", " . (!empty($this->subledger_account) ? ("'" . $this->db->escape($this->subledger_account) . "'") : "NULL");
430
                $sql .= ", " . (!empty($this->subledger_label) ? ("'" . $this->db->escape($this->subledger_label) . "'") : "NULL");
431
                $sql .= ", '" . $this->db->escape($this->numero_compte) . "'";
432
                $sql .= ", " . (!empty($this->label_compte) ? ("'" . $this->db->escape($this->label_compte) . "'") : "NULL");
433
                $sql .= ", '" . $this->db->escape($this->label_operation) . "'";
434
                $sql .= ", " . ((float) $this->debit);
435
                $sql .= ", " . ((float) $this->credit);
436
                $sql .= ", " . ((float) $this->montant);
437
                $sql .= ", " . (!empty($this->sens) ? ("'" . $this->db->escape($this->sens) . "'") : "NULL");
438
                $sql .= ", '" . $this->db->escape($this->fk_user_author) . "'";
439
                $sql .= ", '" . $this->db->idate($now) . "'";
440
                $sql .= ", '" . $this->db->escape($this->code_journal) . "'";
441
                $sql .= ", " . (!empty($this->journal_label) ? ("'" . $this->db->escape($this->journal_label) . "'") : "NULL");
442
                $sql .= ", " . ((int) $this->piece_num);
443
                $sql .= ", " . (!isset($this->entity) ? $conf->entity : $this->entity);
444
                $sql .= ")";
445
446
                $resql = $this->db->query($sql);
447
                if ($resql) {
448
                    $id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
449
450
                    if ($id > 0) {
451
                        $this->id = $id;
452
                        $result = 0;
453
                    } else {
454
                        $result = -2;
455
                        $error++;
456
                        $this->errors[] = 'Error Create Error ' . $result . ' lecture ID';
457
                        dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
458
                    }
459
                } else {
460
                    $result = -1;
461
                    $error++;
462
                    $this->errors[] = 'Error ' . $this->db->lasterror();
463
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
464
                }
465
            } else {    // Already exists
466
                $result = -3;
467
                $error++;
468
                $this->error = 'BookkeepingRecordAlreadyExists';
469
                dol_syslog(__METHOD__ . ' ' . $this->error, LOG_WARNING);
470
            }
471
        } else {
472
            $result = -5;
473
            $error++;
474
            $this->errors[] = 'Error ' . $this->db->lasterror();
475
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
476
        }
477
478
        // Uncomment this and change MYOBJECT to your own tag if you
479
        // want this action to call a trigger.
480
        //if (! $error && ! $notrigger) {
481
482
        // // Call triggers
483
        // $result=$this->call_trigger('MYOBJECT_CREATE',$user);
484
        // if ($result < 0) $error++;
485
        // // End call triggers
486
        //}
487
488
        // Commit or rollback
489
        if ($error) {
490
            $this->db->rollback();
491
            return -1 * $error;
492
        } else {
493
            $this->db->commit();
494
            return $result;
495
        }
496
    }
497
498
    /**
499
     *  Return a link to the object card (with optionally the picto)
500
     *
501
     *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
502
     *  @param  string  $option                     On what the link point to ('nolink', ...)
503
     *  @param  int     $notooltip                  1=Disable tooltip
504
     *  @param  string  $morecss                    Add more css on link
505
     *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
506
     *  @return string                              String with URL
507
     */
508
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
509
    {
510
        global $db, $conf, $langs;
511
        global $dolibarr_main_authentication, $dolibarr_main_demo;
512
        global $menumanager, $hookmanager;
513
514
        if (!empty($conf->dol_no_mouse_hover)) {
515
            $notooltip = 1; // Force disable tooltips
516
        }
517
518
        $result = '';
519
        $companylink = '';
520
521
        $label = '<u>' . $langs->trans("Transaction") . '</u>';
522
        $label .= '<br>';
523
        $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->piece_num;
524
525
        $url = constant('BASE_URL') . '/accountancy/bookkeeping/card.php?piece_num=' . $this->piece_num;
526
527
        if ($option != 'nolink') {
528
            // Add param to save lastsearch_values or not
529
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
530
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
531
                $add_save_lastsearch_values = 1;
532
            }
533
            if ($add_save_lastsearch_values) {
534
                $url .= '&save_lastsearch_values=1';
535
            }
536
        }
537
538
        $linkclose = '';
539
        if (empty($notooltip)) {
540
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
541
                $label = $langs->trans("ShowTransaction");
542
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
543
            }
544
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
545
            $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
546
        } else {
547
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
548
        }
549
550
        $linkstart = '<a href="' . $url . '"';
551
        $linkstart .= $linkclose . '>';
552
        $linkend = '</a>';
553
554
        $result .= $linkstart;
555
        if ($withpicto) {
556
            $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);
557
        }
558
        if ($withpicto != 2) {
559
            $result .= $this->piece_num;
560
        }
561
        $result .= $linkend;
562
        //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
563
564
        global $action;
565
        $hookmanager->initHooks(array($this->element . 'dao'));
566
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
567
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
568
        if ($reshook > 0) {
569
            $result = $hookmanager->resPrint;
570
        } else {
571
            $result .= $hookmanager->resPrint;
572
        }
573
        return $result;
574
    }
575
576
    /**
577
     * Create object into database
578
     *
579
     * @param  User     $user       User that creates
580
     * @param  int      $notrigger  false=launch triggers after, true=disable triggers
581
     * @param  string   $mode       Mode
582
     * @return int                  Return integer <0 if KO, Id of created object if OK
583
     */
584
    public function createStd(User $user, $notrigger = 0, $mode = '')
585
    {
586
        global $conf, $langs;
587
588
        $langs->loadLangs(array("accountancy", "bills", "compta"));
589
590
        dol_syslog(__METHOD__, LOG_DEBUG);
591
592
        $error = 0;
593
594
        // Clean parameters
595
        if (isset($this->doc_type)) {
596
            $this->doc_type = trim($this->doc_type);
597
        }
598
        if (isset($this->doc_ref)) {
599
            $this->doc_ref = trim($this->doc_ref);
600
        }
601
        if (isset($this->fk_doc)) {
602
            $this->fk_doc = (int) $this->fk_doc;
603
        }
604
        if (isset($this->fk_docdet)) {
605
            $this->fk_docdet = (int) $this->fk_docdet;
606
        }
607
        if (isset($this->thirdparty_code)) {
608
            $this->thirdparty_code = trim($this->thirdparty_code);
609
        }
610
        if (isset($this->subledger_account)) {
611
            $this->subledger_account = trim($this->subledger_account);
612
        }
613
        if (isset($this->subledger_label)) {
614
            $this->subledger_label = trim($this->subledger_label);
615
        }
616
        if (isset($this->numero_compte)) {
617
            $this->numero_compte = trim($this->numero_compte);
618
        }
619
        if (isset($this->label_compte)) {
620
            $this->label_compte = trim($this->label_compte);
621
        }
622
        if (isset($this->label_operation)) {
623
            $this->label_operation = trim($this->label_operation);
624
        }
625
        if (isset($this->sens)) {
626
            $this->sens = trim($this->sens);
627
        }
628
        if (isset($this->import_key)) {
629
            $this->import_key = trim($this->import_key);
630
        }
631
        if (isset($this->code_journal)) {
632
            $this->code_journal = trim($this->code_journal);
633
        }
634
        if (isset($this->journal_label)) {
635
            $this->journal_label = trim($this->journal_label);
636
        }
637
        if (isset($this->piece_num)) {
638
            $this->piece_num = (int) $this->piece_num;
639
        }
640
        if (empty($this->debit)) {
641
            $this->debit = 0;
642
        }
643
        if (empty($this->credit)) {
644
            $this->credit = 0;
645
        }
646
        if (empty($this->montant)) {
647
            $this->montant = 0;
648
        }
649
650
        $result = $this->validBookkeepingDate($this->doc_date);
651
        if ($result < 0) {
652
            return -1;
653
        } elseif ($result == 0) {
654
            if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
655
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
656
            } else {
657
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
658
            }
659
            return -1;
660
        }
661
662
        $this->debit = (float) price2num($this->debit, 'MT');
663
        $this->credit = (float) price2num($this->credit, 'MT');
664
        $this->montant = (float) price2num($this->montant, 'MT');
665
666
        $now = dol_now();
667
668
        // Check parameters
669
        $this->journal_label = $langs->trans($this->journal_label);
670
671
        // Insert request
672
        $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . $mode . ' (';
673
        $sql .= 'doc_date,';
674
        $sql .= 'date_lim_reglement,';
675
        $sql .= 'doc_type,';
676
        $sql .= 'doc_ref,';
677
        $sql .= 'fk_doc,';
678
        $sql .= 'fk_docdet,';
679
        $sql .= 'thirdparty_code,';
680
        $sql .= 'subledger_account,';
681
        $sql .= 'subledger_label,';
682
        $sql .= 'numero_compte,';
683
        $sql .= 'label_compte,';
684
        $sql .= 'label_operation,';
685
        $sql .= 'debit,';
686
        $sql .= 'credit,';
687
        $sql .= 'montant,';
688
        $sql .= 'sens,';
689
        $sql .= 'fk_user_author,';
690
        $sql .= 'date_creation,';
691
        $sql .= 'code_journal,';
692
        $sql .= 'journal_label,';
693
        $sql .= 'piece_num,';
694
        $sql .= 'entity';
695
        $sql .= ') VALUES (';
696
        $sql .= ' ' . (!isset($this->doc_date) || dol_strlen($this->doc_date) == 0 ? 'NULL' : "'" . $this->db->idate($this->doc_date) . "'") . ',';
697
        $sql .= ' ' . (!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'" . $this->db->idate($this->date_lim_reglement) . "'") . ',';
698
        $sql .= ' ' . (!isset($this->doc_type) ? 'NULL' : "'" . $this->db->escape($this->doc_type) . "'") . ',';
699
        $sql .= ' ' . (!isset($this->doc_ref) ? 'NULL' : "'" . $this->db->escape($this->doc_ref) . "'") . ',';
700
        $sql .= ' ' . (empty($this->fk_doc) ? '0' : (int) $this->fk_doc) . ',';
701
        $sql .= ' ' . (empty($this->fk_docdet) ? '0' : (int) $this->fk_docdet) . ',';
702
        $sql .= ' ' . (!isset($this->thirdparty_code) ? 'NULL' : "'" . $this->db->escape($this->thirdparty_code) . "'") . ',';
703
        $sql .= ' ' . (!isset($this->subledger_account) ? 'NULL' : "'" . $this->db->escape($this->subledger_account) . "'") . ',';
704
        $sql .= ' ' . (!isset($this->subledger_label) ? 'NULL' : "'" . $this->db->escape($this->subledger_label) . "'") . ',';
705
        $sql .= ' ' . (!isset($this->numero_compte) ? 'NULL' : "'" . $this->db->escape($this->numero_compte) . "'") . ',';
706
        $sql .= ' ' . (!isset($this->label_compte) ? 'NULL' : "'" . $this->db->escape($this->label_compte) . "'") . ',';
707
        $sql .= ' ' . (!isset($this->label_operation) ? 'NULL' : "'" . $this->db->escape($this->label_operation) . "'") . ',';
708
        $sql .= ' ' . (!isset($this->debit) ? 'NULL' : $this->debit) . ',';
709
        $sql .= ' ' . (!isset($this->credit) ? 'NULL' : $this->credit) . ',';
710
        $sql .= ' ' . (!isset($this->montant) ? 'NULL' : $this->montant) . ',';
711
        $sql .= ' ' . (!isset($this->sens) ? 'NULL' : "'" . $this->db->escape($this->sens) . "'") . ',';
712
        $sql .= ' ' . ((int) $user->id) . ',';
713
        $sql .= ' ' . "'" . $this->db->idate($now) . "',";
714
        $sql .= ' ' . (empty($this->code_journal) ? 'NULL' : "'" . $this->db->escape($this->code_journal) . "'") . ',';
715
        $sql .= ' ' . (empty($this->journal_label) ? 'NULL' : "'" . $this->db->escape($this->journal_label) . "'") . ',';
716
        $sql .= ' ' . (empty($this->piece_num) ? 'NULL' : $this->db->escape($this->piece_num)) . ',';
717
        $sql .= ' ' . (!isset($this->entity) ? $conf->entity : $this->entity);
718
        $sql .= ')';
719
720
        $this->db->begin();
721
722
        $resql = $this->db->query($sql);
723
        if (!$resql) {
724
            $error++;
725
            $this->errors[] = 'Error ' . $this->db->lasterror();
726
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
727
        }
728
729
        if (!$error) {
730
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element . $mode);
731
        }
732
733
        // Commit or rollback
734
        if ($error) {
735
            $this->db->rollback();
736
737
            return -1 * $error;
738
        } else {
739
            $this->db->commit();
740
741
            return $this->id;
742
        }
743
    }
744
745
    /**
746
     * Load object in memory from the database
747
     *
748
     * @param int           $id     Id object
749
     * @param string|null   $ref    Ref
750
     * @param string        $mode   Mode ('' or 'tmp_')
751
     * @return int                  Return integer <0 if KO, 0 if not found, >0 if OK
752
     */
753
    public function fetch($id, $ref = null, $mode = '')
754
    {
755
        global $conf;
756
757
        dol_syslog(__METHOD__, LOG_DEBUG);
758
759
        $sql = 'SELECT';
760
        $sql .= ' t.rowid,';
761
        $sql .= " t.doc_date,";
762
        $sql .= " t.date_lim_reglement,";
763
        $sql .= " t.doc_type,";
764
        $sql .= " t.doc_ref,";
765
        $sql .= " t.fk_doc,";
766
        $sql .= " t.fk_docdet,";
767
        $sql .= " t.thirdparty_code,";
768
        $sql .= " t.subledger_account,";
769
        $sql .= " t.subledger_label,";
770
        $sql .= " t.numero_compte,";
771
        $sql .= " t.label_compte,";
772
        $sql .= " t.label_operation,";
773
        $sql .= " t.debit,";
774
        $sql .= " t.credit,";
775
        $sql .= " t.montant as amount,";
776
        $sql .= " t.sens,";
777
        $sql .= " t.fk_user_author,";
778
        $sql .= " t.import_key,";
779
        $sql .= " t.code_journal,";
780
        $sql .= " t.journal_label,";
781
        $sql .= " t.piece_num,";
782
        $sql .= " t.date_creation,";
783
        // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
784
        if ($mode != "_tmp") {
785
            $sql .= " t.date_export,";
786
        }
787
        $sql .= " t.date_validated as date_validation";
788
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . $mode . ' as t';
789
        $sql .= ' WHERE 1 = 1';
790
        $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
791
        if (null !== $ref) {
792
            $sql .= " AND t.rowid = " . ((int) $ref);
793
        } else {
794
            $sql .= " AND t.rowid = " . ((int) $id);
795
        }
796
797
        $resql = $this->db->query($sql);
798
        if ($resql) {
799
            $numrows = $this->db->num_rows($resql);
800
            if ($numrows) {
801
                $obj = $this->db->fetch_object($resql);
802
803
                $this->id = $obj->rowid;
804
805
                $this->doc_date = $this->db->jdate($obj->doc_date);
806
                $this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
807
                $this->doc_type = $obj->doc_type;
808
                $this->doc_ref = $obj->doc_ref;
809
                $this->fk_doc = $obj->fk_doc;
810
                $this->fk_docdet = $obj->fk_docdet;
811
                $this->thirdparty_code = $obj->thirdparty_code;
812
                $this->subledger_account = $obj->subledger_account;
813
                $this->subledger_label = $obj->subledger_label;
814
                $this->numero_compte = $obj->numero_compte;
815
                $this->label_compte = $obj->label_compte;
816
                $this->label_operation = $obj->label_operation;
817
                $this->debit = $obj->debit;
818
                $this->credit = $obj->credit;
819
                $this->montant = $obj->amount;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...s\BookKeeping::$montant has been deprecated: No more used (we have info into debit/credit and sens) ( Ignorable by Annotation )

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

819
                /** @scrutinizer ignore-deprecated */ $this->montant = $obj->amount;

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...
820
                $this->amount = $obj->amount;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...es\BookKeeping::$amount has been deprecated: No more used (we have info into debit/credit and sens) ( Ignorable by Annotation )

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

820
                /** @scrutinizer ignore-deprecated */ $this->amount = $obj->amount;

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...
821
                $this->sens = $obj->sens;
822
                $this->fk_user_author = $obj->fk_user_author;
823
                $this->import_key = $obj->import_key;
824
                $this->code_journal = $obj->code_journal;
825
                $this->journal_label = $obj->journal_label;
826
                $this->piece_num = $obj->piece_num;
827
                $this->date_creation = $this->db->jdate($obj->date_creation);
828
                $this->date_export = $this->db->jdate($obj->date_export);
829
                $this->date_validation = isset($obj->date_validation) ? $this->db->jdate($obj->date_validation) : '';
830
            }
831
            $this->db->free($resql);
832
833
            if ($numrows) {
834
                return 1;
835
            } else {
836
                return 0;
837
            }
838
        } else {
839
            $this->errors[] = 'Error ' . $this->db->lasterror();
840
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
841
842
            return -1;
843
        }
844
    }
845
846
847
    /**
848
     * Load object in memory from the database in ->lines. Or just make a simple count if $countonly=1.
849
     *
850
     * @param   string  $sortorder      Sort Order
851
     * @param   string  $sortfield      Sort field
852
     * @param   int     $limit          limit
853
     * @param   int     $offset         offset limit
854
     * @param   array   $filter         filter array
855
     * @param   string  $filtermode     filter mode (AND or OR)
856
     * @param   int     $option         option (0: general account or 1: subaccount)
857
     * @param   int     $countonly      Do not fill the $object->lines, return only the count.
858
     * @return  int                     Return integer <0 if KO, Number of lines if OK
859
     */
860
    public function fetchAllByAccount($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0, $countonly = 0)
861
    {
862
        global $conf;
863
864
        dol_syslog(__METHOD__, LOG_DEBUG);
865
866
        $this->lines = array();
867
        $num = 0;
868
869
        $sql = 'SELECT';
870
        if ($countonly) {
871
            $sql .= ' COUNT(t.rowid) as nb';
872
        } else {
873
            $sql .= ' t.rowid,';
874
            $sql .= " t.doc_date,";
875
            $sql .= " t.doc_type,";
876
            $sql .= " t.doc_ref,";
877
            $sql .= " t.fk_doc,";
878
            $sql .= " t.fk_docdet,";
879
            $sql .= " t.thirdparty_code,";
880
            $sql .= " t.subledger_account,";
881
            $sql .= " t.subledger_label,";
882
            $sql .= " t.numero_compte,";
883
            $sql .= " t.label_compte,";
884
            $sql .= " t.label_operation,";
885
            $sql .= " t.debit,";
886
            $sql .= " t.credit,";
887
            $sql .= " t.montant as amount,";
888
            $sql .= " t.sens,";
889
            $sql .= " t.multicurrency_amount,";
890
            $sql .= " t.multicurrency_code,";
891
            $sql .= " t.lettering_code,";
892
            $sql .= " t.date_lettering,";
893
            $sql .= " t.fk_user_author,";
894
            $sql .= " t.import_key,";
895
            $sql .= " t.code_journal,";
896
            $sql .= " t.journal_label,";
897
            $sql .= " t.piece_num,";
898
            $sql .= " t.date_creation,";
899
            $sql .= " t.date_export,";
900
            $sql .= " t.date_validated as date_validation,";
901
            $sql .= " t.date_lim_reglement,";
902
            $sql .= " t.import_key";
903
        }
904
        // Manage filter
905
        $sqlwhere = array();
906
        if (count($filter) > 0) {
907
            foreach ($filter as $key => $value) {
908
                if ($key == 't.doc_date>=') {
909
                    $sqlwhere[] = "t.doc_date >= '" . $this->db->idate($value) . "'";
910
                } elseif ($key == 't.doc_date<=') {
911
                    $sqlwhere[] = "t.doc_date <= '" . $this->db->idate($value) . "'";
912
                } elseif ($key == 't.doc_date>') {
913
                    $sqlwhere[] = "t.doc_date > '" . $this->db->idate($value) . "'";
914
                } elseif ($key == 't.doc_date<') {
915
                    $sqlwhere[] = "t.doc_date < '" . $this->db->idate($value) . "'";
916
                } elseif ($key == 't.numero_compte>=') {
917
                    $sqlwhere[] = "t.numero_compte >= '" . $this->db->escape($value) . "'";
918
                } elseif ($key == 't.numero_compte<=') {
919
                    $sqlwhere[] = "t.numero_compte <= '" . $this->db->escape($value) . "'";
920
                } elseif ($key == 't.subledger_account>=') {
921
                    $sqlwhere[] = "t.subledger_account >= '" . $this->db->escape($value) . "'";
922
                } elseif ($key == 't.subledger_account<=') {
923
                    $sqlwhere[] = "t.subledger_account <= '" . $this->db->escape($value) . "'";
924
                } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
925
                    $sqlwhere[] = $this->db->sanitize($key) . ' = ' . ((int) $value);
926
                } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
927
                    $sqlwhere[] = $this->db->sanitize($key) . ' LIKE \'' . $this->db->escape($this->db->escapeforlike($value)) . '%\'';
928
                } elseif ($key == 't.date_creation>=') {
929
                    $sqlwhere[] = 't.date_creation >= \'' . $this->db->idate($value) . '\'';
930
                } elseif ($key == 't.date_creation<=') {
931
                    $sqlwhere[] = 't.date_creation <= \'' . $this->db->idate($value) . '\'';
932
                } elseif ($key == 't.date_export>=') {
933
                    $sqlwhere[] = 't.date_export >= \'' . $this->db->idate($value) . '\'';
934
                } elseif ($key == 't.date_export<=') {
935
                    $sqlwhere[] = 't.date_export <= \'' . $this->db->idate($value) . '\'';
936
                } elseif ($key == 't.date_validated>=') {
937
                    $sqlwhere[] = 't.date_validated >= \'' . $this->db->idate($value) . '\'';
938
                } elseif ($key == 't.date_validated<=') {
939
                    $sqlwhere[] = 't.date_validated <= \'' . $this->db->idate($value) . '\'';
940
                } elseif ($key == 't.date_lim_reglement>=') {
941
                    $sqlwhere[] = 't.date_lim_reglement>=\'' . $this->db->idate($value) . '\'';
942
                } elseif ($key == 't.date_lim_reglement<=') {
943
                    $sqlwhere[] = 't.date_lim_reglement<=\'' . $this->db->idate($value) . '\'';
944
                } elseif ($key == 't.credit' || $key == 't.debit') {
945
                    $sqlwhere[] = natural_search($key, $value, 1, 1);
946
                } elseif ($key == 't.reconciled_option') {
947
                    $sqlwhere[] = 't.lettering_code IS NULL';
948
                } elseif ($key == 't.code_journal' && !empty($value)) {
949
                    if (is_array($value)) {
950
                        $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
951
                    } else {
952
                        $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
953
                    }
954
                } elseif ($key == 't.search_accounting_code_in' && !empty($value)) {
955
                    $sqlwhere[] = 't.numero_compte IN (' . $this->db->sanitize($value, 1) . ')';
956
                } else {
957
                    $sqlwhere[] = natural_search($key, $value, 0, 1);
958
                }
959
            }
960
        }
961
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
962
        $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
963
        if (count($sqlwhere) > 0) {
964
            $sql .= " AND " . implode(" " . $this->db->sanitize($filtermode) . " ", $sqlwhere);
965
        }
966
        // Filter by ledger account or subledger account
967
        if (!empty($option)) {
968
            $sql .= " AND t.subledger_account IS NOT NULL";
969
            $sql .= " AND t.subledger_account <> ''";
970
            $sortfield = 't.subledger_account' . ($sortfield ? ',' . $sortfield : '');
971
            $sortorder = 'ASC' . ($sortfield ? ',' . $sortfield : '');
972
        } else {
973
            $sortfield = 't.numero_compte' . ($sortfield ? ',' . $sortfield : '');
974
            $sortorder = 'ASC' . ($sortorder ? ',' . $sortorder : '');
975
        }
976
977
        if (!$countonly) {
978
            $sql .= $this->db->order($sortfield, $sortorder);
979
            if (!empty($limit)) {
980
                $sql .= $this->db->plimit($limit + 1, $offset);
981
            }
982
        }
983
984
        $resql = $this->db->query($sql);
985
        if ($resql) {
986
            if ($countonly) {
987
                $obj = $this->db->fetch_object($resql);
988
                if ($obj) {
989
                    $num = $obj->nb;
990
                }
991
            } else {
992
                $num = $this->db->num_rows($resql);
993
994
                $i = 0;
995
                while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
996
                    $line = new BookKeepingLine($this->db);
997
998
                    $line->id = $obj->rowid;
999
1000
                    $line->doc_date = $this->db->jdate($obj->doc_date);
1001
                    $line->doc_type = $obj->doc_type;
1002
                    $line->doc_ref = $obj->doc_ref;
1003
                    $line->fk_doc = $obj->fk_doc;
1004
                    $line->fk_docdet = $obj->fk_docdet;
1005
                    $line->thirdparty_code = $obj->thirdparty_code;
1006
                    $line->subledger_account = $obj->subledger_account;
1007
                    $line->subledger_label = $obj->subledger_label;
1008
                    $line->numero_compte = $obj->numero_compte;
1009
                    $line->label_compte = $obj->label_compte;
1010
                    $line->label_operation = $obj->label_operation;
1011
                    $line->debit = $obj->debit;
1012
                    $line->credit = $obj->credit;
1013
                    $line->montant = $obj->amount; // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...okKeepingLine::$montant has been deprecated: see $amount ( Ignorable by Annotation )

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

1013
                    /** @scrutinizer ignore-deprecated */ $line->montant = $obj->amount; // 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...
1014
                    $line->amount = $obj->amount;
1015
                    $line->sens = $obj->sens;
1016
                    $line->multicurrency_amount = $obj->multicurrency_amount;
1017
                    $line->multicurrency_code = $obj->multicurrency_code;
1018
                    $line->lettering_code = $obj->lettering_code;
1019
                    $line->date_lettering = $obj->date_lettering;
1020
                    $line->fk_user_author = $obj->fk_user_author;
1021
                    $line->import_key = $obj->import_key;
1022
                    $line->code_journal = $obj->code_journal;
1023
                    $line->journal_label = $obj->journal_label;
1024
                    $line->piece_num = $obj->piece_num;
1025
                    $line->date_creation = $this->db->jdate($obj->date_creation);
1026
                    $line->date_export = $this->db->jdate($obj->date_export);
1027
                    $line->date_validation = $this->db->jdate($obj->date_validation);
1028
                    // Due date
1029
                    $line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
1030
                    $line->import_key = $obj->import_key;
1031
1032
                    $this->lines[] = $line;
1033
1034
                    $i++;
1035
                }
1036
            }
1037
            $this->db->free($resql);
1038
1039
            return $num;
1040
        } else {
1041
            $this->errors[] = 'Error ' . $this->db->lasterror();
1042
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1043
1044
            return -1;
1045
        }
1046
    }
1047
1048
    /**
1049
     * Load object in memory from the database
1050
     *
1051
     * @param string        $sortorder                      Sort Order
1052
     * @param string        $sortfield                      Sort field
1053
     * @param int           $limit                          Limit
1054
     * @param int           $offset                         Offset limit
1055
     * @param string|array  $filter                         Filter array
1056
     * @param string        $filtermode                     Filter mode (AND or OR)
1057
     * @param int           $showAlreadyExportMovements     Show movements when field 'date_export' is not empty (0:No / 1:Yes (Default))
1058
     * @return int                                          Return integer <0 if KO, >0 if OK
1059
     */
1060
    public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $showAlreadyExportMovements = 1)
1061
    {
1062
        global $conf;
1063
1064
        dol_syslog(__METHOD__, LOG_DEBUG);
1065
1066
        $sql = 'SELECT';
1067
        $sql .= ' t.rowid,';
1068
        $sql .= " t.doc_date,";
1069
        $sql .= " t.doc_type,";
1070
        $sql .= " t.doc_ref,";
1071
        $sql .= " t.fk_doc,";
1072
        $sql .= " t.fk_docdet,";
1073
        $sql .= " t.thirdparty_code,";
1074
        $sql .= " t.subledger_account,";
1075
        $sql .= " t.subledger_label,";
1076
        $sql .= " t.numero_compte,";
1077
        $sql .= " t.label_compte,";
1078
        $sql .= " t.label_operation,";
1079
        $sql .= " t.debit,";
1080
        $sql .= " t.credit,";
1081
        $sql .= " t.lettering_code,";
1082
        $sql .= " t.date_lettering,";
1083
        $sql .= " t.montant as amount,";
1084
        $sql .= " t.sens,";
1085
        $sql .= " t.fk_user_author,";
1086
        $sql .= " t.import_key,";
1087
        $sql .= " t.code_journal,";
1088
        $sql .= " t.journal_label,";
1089
        $sql .= " t.piece_num,";
1090
        $sql .= " t.date_creation,";
1091
        $sql .= " t.date_lim_reglement,";
1092
        $sql .= " t.tms as date_modification,";
1093
        $sql .= " t.date_export,";
1094
        $sql .= " t.date_validated as date_validation";
1095
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
1096
1097
        $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1098
        if ($showAlreadyExportMovements == 0) {
1099
            $sql .= " AND t.date_export IS NULL";
1100
        }
1101
1102
        // Manage filter
1103
        if (is_array($filter)) {    // deprecated, use $filter = USF syntax
1104
            $sqlwhere = array();
1105
            if (count($filter) > 0) {
1106
                foreach ($filter as $key => $value) {
1107
                    if ($key == 't.doc_date') {
1108
                        $sqlwhere[] = $this->db->sanitize($key) . ' = \'' . $this->db->idate($value) . '\'';
1109
                    } elseif ($key == 't.doc_date>=') {
1110
                        $sqlwhere[] = "t.doc_date >= '" . $this->db->idate($value) . "'";
1111
                    } elseif ($key == 't.doc_date<=') {
1112
                        $sqlwhere[] = "t.doc_date <= '" . $this->db->idate($value) . "'";
1113
                    } elseif ($key == 't.doc_date>') {
1114
                        $sqlwhere[] = "t.doc_date > '" . $this->db->idate($value) . "'";
1115
                    } elseif ($key == 't.doc_date<') {
1116
                        $sqlwhere[] = "t.doc_date < '" . $this->db->idate($value) . "'";
1117
                    } elseif ($key == 't.numero_compte>=') {
1118
                        $sqlwhere[] = "t.numero_compte >= '" . $this->db->escape($value) . "'";
1119
                    } elseif ($key == 't.numero_compte<=') {
1120
                        $sqlwhere[] = "t.numero_compte <= '" . $this->db->escape($value) . "'";
1121
                    } elseif ($key == 't.subledger_account>=') {
1122
                        $sqlwhere[] = "t.subledger_account >= '" . $this->db->escape($value) . "'";
1123
                    } elseif ($key == 't.subledger_account<=') {
1124
                        $sqlwhere[] = "t.subledger_account <= '" . $this->db->escape($value) . "'";
1125
                    } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1126
                        $sqlwhere[] = $this->db->sanitize($key) . ' = ' . ((int) $value);
1127
                    } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1128
                        $sqlwhere[] = $this->db->sanitize($key) . ' LIKE \'' . $this->db->escape($value) . '%\'';
1129
                    } elseif ($key == 't.date_creation>=') {
1130
                        $sqlwhere[] = 't.date_creation >= \'' . $this->db->idate($value) . '\'';
1131
                    } elseif ($key == 't.date_creation<=') {
1132
                        $sqlwhere[] = 't.date_creation <= \'' . $this->db->idate($value) . '\'';
1133
                    } elseif ($key == 't.tms>=') {
1134
                        $sqlwhere[] = 't.tms >= \'' . $this->db->idate($value) . '\'';
1135
                    } elseif ($key == 't.tms<=') {
1136
                        $sqlwhere[] = 't.tms <= \'' . $this->db->idate($value) . '\'';
1137
                    } elseif ($key == 't.date_export>=') {
1138
                        $sqlwhere[] = 't.date_export >= \'' . $this->db->idate($value) . '\'';
1139
                    } elseif ($key == 't.date_export<=') {
1140
                        $sqlwhere[] = 't.date_export <= \'' . $this->db->idate($value) . '\'';
1141
                    } elseif ($key == 't.date_validated>=') {
1142
                        $sqlwhere[] = 't.date_validated >= \'' . $this->db->idate($value) . '\'';
1143
                    } elseif ($key == 't.date_validated<=') {
1144
                        $sqlwhere[] = 't.date_validated <= \'' . $this->db->idate($value) . '\'';
1145
                    } elseif ($key == 't.credit' || $key == 't.debit') {
1146
                        $sqlwhere[] = natural_search($key, $value, 1, 1);
1147
                    } elseif ($key == 't.code_journal' && !empty($value)) {
1148
                        if (is_array($value)) {
1149
                            $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1150
                        } else {
1151
                            $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1152
                        }
1153
                    } else {
1154
                        $sqlwhere[] = natural_search($key, $value, 0, 1);
1155
                    }
1156
                }
1157
            }
1158
            if (count($sqlwhere) > 0) {
1159
                $sql .= ' AND ' . implode(" " . $this->db->sanitize($filtermode) . " ", $sqlwhere);
1160
            }
1161
1162
            $filter = '';
1163
        }
1164
1165
        // Manage filter
1166
        $errormessage = '';
1167
        $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1168
        if ($errormessage) {
1169
            $this->errors[] = $errormessage;
1170
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1171
            return -1;
1172
        }
1173
1174
        if (!empty($sortfield)) {
1175
            $sql .= $this->db->order($sortfield, $sortorder);
1176
        }
1177
        if (!empty($limit)) {
1178
            $sql .= $this->db->plimit($limit + 1, $offset);
1179
        }
1180
        $this->lines = array();
1181
1182
        $resql = $this->db->query($sql);
1183
        if ($resql) {
1184
            $num = $this->db->num_rows($resql);
1185
1186
            $i = 0;
1187
            while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1188
                $line = new BookKeepingLine($this->db);
1189
1190
                $line->id = $obj->rowid;
1191
1192
                $line->doc_date = $this->db->jdate($obj->doc_date);
1193
                $line->doc_type = $obj->doc_type;
1194
                $line->doc_ref = $obj->doc_ref;
1195
                $line->fk_doc = $obj->fk_doc;
1196
                $line->fk_docdet = $obj->fk_docdet;
1197
                $line->thirdparty_code = $obj->thirdparty_code;
1198
                $line->subledger_account = $obj->subledger_account;
1199
                $line->subledger_label = $obj->subledger_label;
1200
                $line->numero_compte = $obj->numero_compte;
1201
                $line->label_compte = $obj->label_compte;
1202
                $line->label_operation = $obj->label_operation;
1203
                $line->debit = $obj->debit;
1204
                $line->credit = $obj->credit;
1205
                $line->montant = $obj->amount; // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...okKeepingLine::$montant has been deprecated: see $amount ( Ignorable by Annotation )

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

1205
                /** @scrutinizer ignore-deprecated */ $line->montant = $obj->amount; // 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...
1206
                $line->amount = $obj->amount;
1207
                $line->sens = $obj->sens;
1208
                $line->lettering_code = $obj->lettering_code;
1209
                $line->date_lettering = $obj->date_lettering;
1210
                $line->fk_user_author = $obj->fk_user_author;
1211
                $line->import_key = $obj->import_key;
1212
                $line->code_journal = $obj->code_journal;
1213
                $line->journal_label = $obj->journal_label;
1214
                $line->piece_num = $obj->piece_num;
1215
                $line->date_creation = $this->db->jdate($obj->date_creation);
1216
                $line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
1217
                $line->date_modification = $this->db->jdate($obj->date_modification);
1218
                $line->date_export = $this->db->jdate($obj->date_export);
1219
                $line->date_validation = $this->db->jdate($obj->date_validation);
1220
1221
                $this->lines[] = $line;
1222
1223
                $i++;
1224
            }
1225
            $this->db->free($resql);
1226
1227
            return $num;
1228
        } else {
1229
            $this->errors[] = 'Error ' . $this->db->lasterror();
1230
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1231
            return -1;
1232
        }
1233
    }
1234
1235
    /**
1236
     * Load object in memory from the database
1237
     *
1238
     * @param   string          $sortorder      Sort Order
1239
     * @param   string          $sortfield      Sort field
1240
     * @param   int             $limit          Limit
1241
     * @param   int             $offset         Offset limit
1242
     * @param   string|array    $filter         Filter
1243
     * @param   string          $filtermode     Filter mode (AND or OR)
1244
     * @param   int             $option         option (0: aggregate by general account or 1: aggreegate by subaccount)
1245
     * @return  int                             Return integer <0 if KO, >0 if OK
1246
     */
1247
    public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $option = 0)
1248
    {
1249
        global $conf;
1250
1251
        $this->lines = array();
1252
1253
        dol_syslog(__METHOD__, LOG_DEBUG);
1254
1255
        $sql = 'SELECT';
1256
        $sql .= " t.numero_compte,";
1257
        if (!empty($option)) {
1258
            $sql .= " t.subledger_account,";
1259
            $sql .= " t.subledger_label,";
1260
        }
1261
        $sql .= " SUM(t.debit) as debit,";
1262
        $sql .= " SUM(t.credit) as credit";
1263
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
1264
        $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1265
1266
        // Manage filter
1267
        if (is_array($filter)) {
1268
            $sqlwhere = array();
1269
            if (count($filter) > 0) {
1270
                foreach ($filter as $key => $value) {
1271
                    if ($key == 't.doc_date') {
1272
                        $sqlwhere[] = $this->db->sanitize($key) . " = '" . $this->db->idate($value) . "'";
1273
                    } elseif ($key == 't.doc_date>=') {
1274
                        $sqlwhere[] = "t.doc_date >= '" . $this->db->idate($value) . "'";
1275
                    } elseif ($key == 't.doc_date<=') {
1276
                        $sqlwhere[] = "t.doc_date <= '" . $this->db->idate($value) . "'";
1277
                    } elseif ($key == 't.doc_date>') {
1278
                        $sqlwhere[] = "t.doc_date > '" . $this->db->idate($value) . "'";
1279
                    } elseif ($key == 't.doc_date<') {
1280
                        $sqlwhere[] = "t.doc_date < '" . $this->db->idate($value) . "'";
1281
                    } elseif ($key == 't.numero_compte>=') {
1282
                        $sqlwhere[] = "t.numero_compte >= '" . $this->db->escape($value) . "'";
1283
                    } elseif ($key == 't.numero_compte<=') {
1284
                        $sqlwhere[] = "t.numero_compte <= '" . $this->db->escape($value) . "'";
1285
                    } elseif ($key == 't.subledger_account>=') {
1286
                        $sqlwhere[] = "t.subledger_account >= '" . $this->db->escape($value) . "'";
1287
                    } elseif ($key == 't.subledger_account<=') {
1288
                        $sqlwhere[] = "t.subledger_account <= '" . $this->db->escape($value) . "'";
1289
                    } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1290
                        $sqlwhere[] = $this->db->sanitize($key) . " = " . ((int) $value);
1291
                    } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1292
                        $sqlwhere[] = $this->db->sanitize($key) . " LIKE '" . $this->db->escape($value) . "%'";
1293
                    } elseif ($key == 't.subledger_label') {
1294
                        $sqlwhere[] = $this->db->sanitize($key) . " LIKE '" . $this->db->escape($value) . "%'";
1295
                    } elseif ($key == 't.code_journal' && !empty($value)) {
1296
                        if (is_array($value)) {
1297
                            $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1298
                        } else {
1299
                            $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1300
                        }
1301
                    } elseif ($key == 't.reconciled_option') {
1302
                        $sqlwhere[] = 't.lettering_code IS NULL';
1303
                    } else {
1304
                        $sqlwhere[] = $this->db->sanitize($key) . " LIKE '%" . $this->db->escape($this->db->escapeforlike($value)) . "%'";
1305
                    }
1306
                }
1307
            }
1308
            if (count($sqlwhere) > 0) {
1309
                $sql .= " AND " . implode(" " . $this->db->sanitize($filtermode) . " ", $sqlwhere);
1310
            }
1311
1312
            $filter = '';
1313
        }
1314
1315
        // Manage filter
1316
        $errormessage = '';
1317
        $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1318
        if ($errormessage) {
1319
            $this->errors[] = $errormessage;
1320
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1321
            return -1;
1322
        }
1323
1324
        if (!empty($option)) {
1325
            $sql .= " AND t.subledger_account IS NOT NULL";
1326
            $sql .= " AND t.subledger_account <> ''";
1327
            $sql .= " GROUP BY t.numero_compte, t.subledger_account, t.subledger_label";
1328
            $sortfield = 't.subledger_account' . ($sortfield ? ',' . $sortfield : '');
1329
            $sortorder = 'ASC' . ($sortfield ? ',' . $sortfield : '');
1330
        } else {
1331
            $sql .= ' GROUP BY t.numero_compte';
1332
            $sortfield = 't.numero_compte' . ($sortfield ? ',' . $sortfield : '');
1333
            $sortorder = 'ASC' . ($sortorder ? ',' . $sortorder : '');
1334
        }
1335
1336
        if (!empty($sortfield)) {
1337
            $sql .= $this->db->order($sortfield, $sortorder);
1338
        }
1339
        if (!empty($limit)) {
1340
            $sql .= $this->db->plimit($limit + 1, $offset);
1341
        }
1342
1343
        //print $sql;
1344
        $resql = $this->db->query($sql);
1345
1346
        if ($resql) {
1347
            $num = $this->db->num_rows($resql);
1348
1349
            $i = 0;
1350
            while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1351
                $line = new BookKeepingLine($this->db);
1352
1353
                $line->numero_compte = $obj->numero_compte;
1354
                //$line->label_compte = $obj->label_compte;
1355
                if (!empty($option)) {
1356
                    $line->subledger_account = $obj->subledger_account;
1357
                    $line->subledger_label = $obj->subledger_label;
1358
                }
1359
                $line->debit = $obj->debit;
1360
                $line->credit = $obj->credit;
1361
1362
                $this->lines[] = $line;
1363
1364
                $i++;
1365
            }
1366
            $this->db->free($resql);
1367
1368
            return $num;
1369
        } else {
1370
            $this->errors[] = 'Error ' . $this->db->lasterror();
1371
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1372
1373
            return -1;
1374
        }
1375
    }
1376
1377
    /**
1378
     * Update object into database
1379
     *
1380
     * @param  User     $user       User that modifies
1381
     * @param  int      $notrigger  false=launch triggers after, true=disable triggers
1382
     * @param  string   $mode       Mode ('' or _tmp')
1383
     * @return int                  Return integer <0 if KO, >0 if OK
1384
     */
1385
    public function update(User $user, $notrigger = 0, $mode = '')
1386
    {
1387
        global $langs;
1388
        $error = 0;
1389
1390
        dol_syslog(__METHOD__, LOG_DEBUG);
1391
1392
        // Clean parameters
1393
        if (isset($this->doc_type)) {
1394
            $this->doc_type = trim($this->doc_type);
1395
        }
1396
        if (isset($this->doc_ref)) {
1397
            $this->doc_ref = trim($this->doc_ref);
1398
        }
1399
        if (isset($this->fk_doc)) {
1400
            $this->fk_doc = (int) $this->fk_doc;
1401
        }
1402
        if (isset($this->fk_docdet)) {
1403
            $this->fk_docdet = (int) $this->fk_docdet;
1404
        }
1405
        if (isset($this->thirdparty_code)) {
1406
            $this->thirdparty_code = trim($this->thirdparty_code);
1407
        }
1408
        if (isset($this->subledger_account)) {
1409
            $this->subledger_account = trim($this->subledger_account);
1410
        }
1411
        if (isset($this->subledger_label)) {
1412
            $this->subledger_label = trim($this->subledger_label);
1413
        }
1414
        if (isset($this->numero_compte)) {
1415
            $this->numero_compte = trim($this->numero_compte);
1416
        }
1417
        if (isset($this->label_compte)) {
1418
            $this->label_compte = trim($this->label_compte);
1419
        }
1420
        if (isset($this->label_operation)) {
1421
            $this->label_operation = trim($this->label_operation);
1422
        }
1423
        if (isset($this->sens)) {
1424
            $this->sens = trim($this->sens);
1425
        }
1426
        if (isset($this->import_key)) {
1427
            $this->import_key = trim($this->import_key);
1428
        }
1429
        if (isset($this->code_journal)) {
1430
            $this->code_journal = trim($this->code_journal);
1431
        }
1432
        if (isset($this->journal_label)) {
1433
            $this->journal_label = trim($this->journal_label);
1434
        }
1435
        if (isset($this->piece_num)) {
1436
            $this->piece_num = (int) $this->piece_num;
1437
        }
1438
1439
        $result = $this->canModifyBookkeeping($this->id, $mode);
1440
        if ($result < 0) {
1441
            return -1;
1442
        } elseif ($result == 0) {
1443
            if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1444
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1445
            } else {
1446
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1447
            }
1448
            return -1;
1449
        }
1450
1451
        $this->debit = (float) price2num($this->debit, 'MT');
1452
        $this->credit = (float) price2num($this->credit, 'MT');
1453
        $this->montant = (float) price2num($this->montant, 'MT');
1454
1455
        // Check parameters
1456
        // Put here code to add a control on parameters values
1457
1458
        // Update request
1459
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . $mode . ' SET';
1460
        $sql .= ' doc_date = ' . (!isset($this->doc_date) || dol_strlen($this->doc_date) != 0 ? "'" . $this->db->idate($this->doc_date) . "'" : 'null') . ',';
1461
        $sql .= ' doc_type = ' . (isset($this->doc_type) ? "'" . $this->db->escape($this->doc_type) . "'" : "null") . ',';
1462
        $sql .= ' doc_ref = ' . (isset($this->doc_ref) ? "'" . $this->db->escape($this->doc_ref) . "'" : "null") . ',';
1463
        $sql .= ' fk_doc = ' . (isset($this->fk_doc) ? $this->fk_doc : "null") . ',';
1464
        $sql .= ' fk_docdet = ' . (isset($this->fk_docdet) ? $this->fk_docdet : "null") . ',';
1465
        $sql .= ' thirdparty_code = ' . (isset($this->thirdparty_code) ? "'" . $this->db->escape($this->thirdparty_code) . "'" : "null") . ',';
1466
        $sql .= ' subledger_account = ' . (isset($this->subledger_account) ? "'" . $this->db->escape($this->subledger_account) . "'" : "null") . ',';
1467
        $sql .= ' subledger_label = ' . (isset($this->subledger_label) ? "'" . $this->db->escape($this->subledger_label) . "'" : "null") . ',';
1468
        $sql .= ' numero_compte = ' . (isset($this->numero_compte) ? "'" . $this->db->escape($this->numero_compte) . "'" : "null") . ',';
1469
        $sql .= ' label_compte = ' . (isset($this->label_compte) ? "'" . $this->db->escape($this->label_compte) . "'" : "null") . ',';
1470
        $sql .= ' label_operation = ' . (isset($this->label_operation) ? "'" . $this->db->escape($this->label_operation) . "'" : "null") . ',';
1471
        $sql .= ' debit = ' . (isset($this->debit) ? $this->debit : "null") . ',';
1472
        $sql .= ' credit = ' . (isset($this->credit) ? $this->credit : "null") . ',';
1473
        $sql .= ' montant = ' . (isset($this->montant) ? $this->montant : "null") . ',';
1474
        $sql .= ' sens = ' . (isset($this->sens) ? "'" . $this->db->escape($this->sens) . "'" : "null") . ',';
1475
        $sql .= ' fk_user_author = ' . (isset($this->fk_user_author) ? $this->fk_user_author : "null") . ',';
1476
        $sql .= ' import_key = ' . (isset($this->import_key) ? "'" . $this->db->escape($this->import_key) . "'" : "null") . ',';
1477
        $sql .= ' code_journal = ' . (isset($this->code_journal) ? "'" . $this->db->escape($this->code_journal) . "'" : "null") . ',';
1478
        $sql .= ' journal_label = ' . (isset($this->journal_label) ? "'" . $this->db->escape($this->journal_label) . "'" : "null") . ',';
1479
        $sql .= ' piece_num = ' . (isset($this->piece_num) ? $this->piece_num : "null");
1480
        $sql .= ' WHERE rowid=' . ((int) $this->id);
1481
1482
        $this->db->begin();
1483
1484
        $resql = $this->db->query($sql);
1485
        if (!$resql) {
1486
            $error++;
1487
            $this->errors[] = 'Error ' . $this->db->lasterror();
1488
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1489
        }
1490
1491
        // Uncomment this and change MYOBJECT to your own tag if you
1492
        // want this action calls a trigger.
1493
        //if (! $error && ! $notrigger) {
1494
1495
        // // Call triggers
1496
        // $result=$this->call_trigger('MYOBJECT_MODIFY',$user);
1497
        // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1498
        // // End call triggers
1499
        //}
1500
1501
        // Commit or rollback
1502
        if ($error) {
1503
            $this->db->rollback();
1504
1505
            return -1 * $error;
1506
        } else {
1507
            $this->db->commit();
1508
1509
            return 1;
1510
        }
1511
    }
1512
1513
    /**
1514
     * Update accounting movement
1515
     *
1516
     * @param  string  $piece_num      Piece num
1517
     * @param  string  $field          Field
1518
     * @param  string  $value          Value
1519
     * @param  string  $mode           Mode ('' or _tmp')
1520
     * @return int                     Return integer <0 if KO, >0 if OK
1521
     */
1522
    public function updateByMvt($piece_num = '', $field = '', $value = '', $mode = '')
1523
    {
1524
        $error = 0;
1525
1526
        $sql_filter = $this->getCanModifyBookkeepingSQL();
1527
        if (!isset($sql_filter)) {
1528
            return -1;
1529
        }
1530
1531
        $this->db->begin();
1532
1533
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . $mode;
1534
        $sql .= " SET " . $this->db->sanitize($field) . " = " . (is_numeric($value) ? ((float) $value) : "'" . $this->db->escape($value) . "'");
1535
        $sql .= " WHERE piece_num = " . ((int) $piece_num);
1536
        $sql .= $sql_filter;
1537
1538
        $resql = $this->db->query($sql);
1539
1540
        if (!$resql) {
1541
            $error++;
1542
            $this->errors[] = 'Error ' . $this->db->lasterror();
1543
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1544
        }
1545
        if ($error) {
1546
            $this->db->rollback();
1547
1548
            return -1 * $error;
1549
        } else {
1550
            $this->db->commit();
1551
1552
            return 1;
1553
        }
1554
    }
1555
1556
    /**
1557
     * Delete object in database
1558
     *
1559
     * @param User      $user       User that deletes
1560
     * @param int       $notrigger  0=launch triggers after, 1=disable triggers
1561
     * @param string    $mode       Mode ('' or 'tmp_')
1562
     * @return int                  Return integer <0 if KO, >0 if OK
1563
     */
1564
    public function delete(User $user, $notrigger = 0, $mode = '')
1565
    {
1566
        global $langs;
1567
1568
        dol_syslog(__METHOD__, LOG_DEBUG);
1569
1570
        $result = $this->canModifyBookkeeping($this->id, $mode);
1571
        if ($result < 0) {
1572
            return -1;
1573
        } elseif ($result == 0) {
1574
            if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1575
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1576
            } else {
1577
                $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1578
            }
1579
            return -1;
1580
        }
1581
1582
        $error = 0;
1583
1584
        $this->db->begin();
1585
1586
        // Uncomment this and change MYOBJECT to your own tag if you
1587
        // want this action calls a trigger.
1588
        //if (! $error && ! $notrigger) {
1589
1590
        // // Call triggers
1591
        // $result=$this->call_trigger('MYOBJECT_DELETE',$user);
1592
        // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1593
        // // End call triggers
1594
        //}
1595
1596
        if (!$error) {
1597
            $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . $mode;
1598
            $sql .= ' WHERE rowid=' . ((int) $this->id);
1599
1600
            $resql = $this->db->query($sql);
1601
            if (!$resql) {
1602
                $error++;
1603
                $this->errors[] = 'Error ' . $this->db->lasterror();
1604
                dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1605
            }
1606
        }
1607
1608
        // Commit or rollback
1609
        if ($error) {
1610
            $this->db->rollback();
1611
1612
            return -1 * $error;
1613
        } else {
1614
            $this->db->commit();
1615
1616
            return 1;
1617
        }
1618
    }
1619
1620
    /**
1621
     * Delete bookkeeping by importkey
1622
     *
1623
     * @param  string       $importkey      Import key
1624
     * @param string $mode Mode
1625
     * @return int Result
1626
     */
1627
    public function deleteByImportkey($importkey, $mode = '')
1628
    {
1629
        $this->db->begin();
1630
1631
        $sql_filter = $this->getCanModifyBookkeepingSQL();
1632
        if (!isset($sql_filter)) {
1633
            return -1;
1634
        }
1635
1636
        // first check if line not yet in bookkeeping
1637
        $sql = "DELETE";
1638
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode;
1639
        $sql .= " WHERE import_key = '" . $this->db->escape($importkey) . "'";
1640
        $sql .= $sql_filter;
1641
1642
        $resql = $this->db->query($sql);
1643
1644
        if (!$resql) {
1645
            $this->errors[] = "Error " . $this->db->lasterror();
1646
            dol_syslog(get_class($this) . "::delete Error " . $this->db->lasterror(), LOG_ERR);
1647
            $this->db->rollback();
1648
            return -1;
1649
        }
1650
1651
        $this->db->commit();
1652
        return 1;
1653
    }
1654
1655
    /**
1656
     * Delete bookkeeping by year
1657
     *
1658
     * @param  int    $delyear      Year to delete
1659
     * @param  string $journal      Journal to delete
1660
     * @param  string $mode         Mode
1661
     * @param  int    $delmonth     Month
1662
     * @return int                  Return integer <0 if KO, >0 if OK
1663
     */
1664
    public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0)
1665
    {
1666
        global $conf, $langs;
1667
1668
        if (empty($delyear) && empty($journal)) {
1669
            $this->error = 'ErrorOneFieldRequired';
1670
            return -1;
1671
        }
1672
        if (!empty($delmonth) && empty($delyear)) {
1673
            $this->error = 'YearRequiredIfMonthDefined';
1674
            return -2;
1675
        }
1676
1677
        $sql_filter = $this->getCanModifyBookkeepingSQL();
1678
        if (!isset($sql_filter)) {
1679
            return -1;
1680
        }
1681
1682
        $this->db->begin();
1683
1684
        // Delete record in bookkeeping
1685
        $sql = "DELETE";
1686
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode;
1687
        $sql .= " WHERE 1 = 1";
1688
        $sql .= dolSqlDateFilter('doc_date', 0, $delmonth, $delyear);
1689
        if (!empty($journal)) {
1690
            $sql .= " AND code_journal = '" . $this->db->escape($journal) . "'";
1691
        }
1692
        $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1693
        // Exclusion of validated entries at the time of deletion
1694
        $sql .= " AND date_validated IS NULL";
1695
        $sql .= $sql_filter;
1696
1697
        // TODO: In a future we must forbid deletion if record is inside a closed fiscal period.
1698
1699
        $resql = $this->db->query($sql);
1700
1701
        if (!$resql) {
1702
            $this->errors[] = "Error " . $this->db->lasterror();
1703
            foreach ($this->errors as $errmsg) {
1704
                dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR);
1705
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
1706
            }
1707
            $this->db->rollback();
1708
            return -1;
1709
        }
1710
1711
        $this->db->commit();
1712
        return 1;
1713
    }
1714
1715
    /**
1716
     * Delete bookkeeping by piece number
1717
     *
1718
     * @param   int     $piecenum   Piecenum to delete
1719
     * @param   string  $mode       Mode ('' or '_tmp')
1720
     * @return  int                 Result
1721
     */
1722
    public function deleteMvtNum($piecenum, $mode = '')
1723
    {
1724
        global $conf;
1725
1726
        $sql_filter = $this->getCanModifyBookkeepingSQL();
1727
        if (!isset($sql_filter)) {
1728
            return -1;
1729
        }
1730
1731
        $this->db->begin();
1732
1733
        // first check if line not yet in bookkeeping
1734
        $sql = "DELETE";
1735
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode;
1736
        $sql .= " WHERE piece_num = " . (int) $piecenum;
1737
        $sql .= " AND date_validated IS NULL";      // For security, exclusion of validated entries at the time of deletion
1738
        $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1739
        $sql .= $sql_filter;
1740
1741
        $resql = $this->db->query($sql);
1742
1743
        if (!$resql) {
1744
            $this->errors[] = "Error " . $this->db->lasterror();
1745
            foreach ($this->errors as $errmsg) {
1746
                dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR);
1747
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
1748
            }
1749
            $this->db->rollback();
1750
            return -1;
1751
        }
1752
1753
        $this->db->commit();
1754
        return 1;
1755
    }
1756
1757
    /**
1758
     * Load an object from its id and create a new one in database
1759
     *
1760
     * @param   User    $user       User making the clone
1761
     * @param   int     $fromid     Id of object to clone
1762
     * @return  int                 New id of clone
1763
     */
1764
    public function createFromClone(User $user, $fromid)
1765
    {
1766
        dol_syslog(__METHOD__, LOG_DEBUG);
1767
1768
        $error = 0;
1769
        $object = new BookKeeping($this->db);
1770
1771
        $this->db->begin();
1772
1773
        // Load source object
1774
        $object->fetch($fromid);
1775
        // Reset object
1776
        $object->id = 0;
1777
1778
        // Clear fields
1779
        // ...
1780
1781
        // Create clone
1782
        $object->context['createfromclone'] = 'createfromclone';
1783
        $result = $object->create($user);
1784
1785
        // Other options
1786
        if ($result < 0) {
1787
            $error++;
1788
            $this->errors = $object->errors;
1789
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
1790
        }
1791
1792
        unset($object->context['createfromclone']);
1793
1794
        // End
1795
        if (!$error) {
1796
            $this->db->commit();
1797
1798
            return $object->id;
1799
        } else {
1800
            $this->db->rollback();
1801
1802
            return -1;
1803
        }
1804
    }
1805
1806
    /**
1807
     * Initialise object with example values
1808
     * Id must be 0 if object instance is a specimen
1809
     *
1810
     * @return int
1811
     */
1812
    public function initAsSpecimen()
1813
    {
1814
        global $user;
1815
1816
        $now = dol_now();
1817
1818
        $this->id = 0;
1819
        $this->doc_date = $now;
1820
        $this->doc_type = '';
1821
        $this->doc_ref = '';
1822
        $this->fk_doc = 0;
1823
        $this->fk_docdet = 0;
1824
        $this->thirdparty_code = 'CU001';
1825
        $this->subledger_account = '41100001';
1826
        $this->subledger_label = 'My customer company';
1827
        $this->numero_compte = '411';
1828
        $this->label_compte = 'Customer';
1829
        $this->label_operation = 'Sales of pea';
1830
        $this->debit = 99.9;
1831
        $this->credit = 0.0;
1832
        $this->amount = 0.0;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...es\BookKeeping::$amount has been deprecated: No more used (we have info into debit/credit and sens) ( Ignorable by Annotation )

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

1832
        /** @scrutinizer ignore-deprecated */ $this->amount = 0.0;

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...
1833
        $this->sens = 'D';
1834
        $this->fk_user_author = $user->id;
1835
        $this->import_key = '20201027';
1836
        $this->code_journal = 'VT';
1837
        $this->journal_label = 'Journal de vente';
1838
        $this->piece_num = 1234;
1839
        $this->date_creation = $now;
1840
1841
        return 1;
1842
    }
1843
1844
    /**
1845
     * Load an accounting document into memory from database
1846
     *
1847
     * @param int $piecenum Accounting document to get
1848
     * @param string $mode Mode
1849
     * @return int Return integer <0 if KO, >0 if OK
1850
     */
1851
    public function fetchPerMvt($piecenum, $mode = '')
1852
    {
1853
        global $conf;
1854
1855
        $sql = "SELECT piece_num, doc_date, code_journal, journal_label, doc_ref, doc_type,";
1856
        $sql .= " date_creation, tms as date_modification, date_validated as date_validation, date_lim_reglement, import_key";
1857
        // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1858
        if ($mode != "_tmp") {
1859
            $sql .= ", date_export";
1860
        }
1861
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode;
1862
        $sql .= " WHERE piece_num = " . ((int) $piecenum);
1863
        $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1864
1865
        dol_syslog(__METHOD__, LOG_DEBUG);
1866
        $result = $this->db->query($sql);
1867
        if ($result) {
1868
            $obj = $this->db->fetch_object($result);
1869
1870
            $this->piece_num = $obj->piece_num;
1871
            $this->code_journal = $obj->code_journal;
1872
            $this->journal_label = $obj->journal_label;
1873
            $this->doc_date = $this->db->jdate($obj->doc_date);
1874
            $this->doc_ref = $obj->doc_ref;
1875
            $this->doc_type = $obj->doc_type;
1876
            $this->date_creation = $this->db->jdate($obj->date_creation);
1877
            $this->date_modification = $this->db->jdate($obj->date_modification);
1878
            if ($mode != "_tmp") {
1879
                $this->date_export = $this->db->jdate($obj->date_export);
1880
            }
1881
            $this->date_validation = $this->db->jdate($obj->date_validation);
1882
            $this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
1883
            $this->import_key = $obj->import_key;
1884
        } else {
1885
            $this->error = "Error " . $this->db->lasterror();
1886
            dol_syslog(__METHOD__ . $this->error, LOG_ERR);
1887
            return -1;
1888
        }
1889
1890
        return 1;
1891
    }
1892
1893
    /**
1894
     * Return next movement number
1895
     *
1896
     * @param   string  $mode       Mode
1897
     * @return  int<1, max>|-1      Return next movement number or -1 if error
1898
     */
1899
    public function getNextNumMvt($mode = '')
1900
    {
1901
        global $conf;
1902
1903
        $sql = "SELECT MAX(piece_num)+1 as max FROM " . MAIN_DB_PREFIX . $this->table_element . $mode;
1904
        $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1905
1906
        dol_syslog(get_class($this) . "::getNextNumMvt", LOG_DEBUG);
1907
1908
        $result = $this->db->query($sql);
1909
1910
        if ($result) {
1911
            $obj = $this->db->fetch_object($result);
1912
            if ($obj) {
1913
                $result = $obj->max;
1914
            }
1915
            if (empty($result)) {
1916
                $result = 1;
1917
            }
1918
            return $result;
1919
        } else {
1920
            $this->error = "Error " . $this->db->lasterror();
1921
            dol_syslog(get_class($this) . "::getNextNumMvt " . $this->error, LOG_ERR);
1922
            return -1;
1923
        }
1924
    }
1925
1926
    /**
1927
     * Load all accounting lines related to a given transaction ID $piecenum
1928
     *
1929
     * @param  int     $piecenum   Id of line to get
1930
     * @param  string  $mode       Mode ('' or '_tmp')
1931
     * @return int                 Return integer <0 if KO, >0 if OK
1932
     */
1933
    public function fetchAllPerMvt($piecenum, $mode = '')
1934
    {
1935
        global $conf;
1936
1937
        $sql = "SELECT rowid, doc_date, doc_type,";
1938
        $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1939
        $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1940
        $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, journal_label, piece_num,";
1941
        $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1942
        // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1943
        if ($mode != "_tmp") {
1944
            $sql .= ", date_export";
1945
        }
1946
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode;
1947
        $sql .= " WHERE piece_num = " . ((int) $piecenum);
1948
        $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1949
1950
        dol_syslog(__METHOD__, LOG_DEBUG);
1951
        $result = $this->db->query($sql);
1952
        if ($result) {
1953
            while ($obj = $this->db->fetch_object($result)) {
1954
                $line = new BookKeepingLine($this->db);
1955
1956
                $line->id = $obj->rowid;
1957
1958
                $line->doc_date = $this->db->jdate($obj->doc_date);
1959
                $line->doc_type = $obj->doc_type;
1960
                $line->doc_ref = $obj->doc_ref;
1961
                $line->fk_doc = $obj->fk_doc;
1962
                $line->fk_docdet = $obj->fk_docdet;
1963
                $line->thirdparty_code = $obj->thirdparty_code;
1964
                $line->subledger_account = $obj->subledger_account;
1965
                $line->subledger_label = $obj->subledger_label;
1966
                $line->numero_compte = $obj->numero_compte;
1967
                $line->label_compte = $obj->label_compte;
1968
                $line->label_operation = $obj->label_operation;
1969
                $line->debit = $obj->debit;
1970
                $line->credit = $obj->credit;
1971
                $line->montant = $obj->amount;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...okKeepingLine::$montant has been deprecated: see $amount ( Ignorable by Annotation )

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

1971
                /** @scrutinizer ignore-deprecated */ $line->montant = $obj->amount;

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...
1972
                $line->amount = $obj->amount;
1973
                $line->sens = $obj->sens;
1974
                $line->code_journal = $obj->code_journal;
1975
                $line->journal_label = $obj->journal_label;
1976
                $line->piece_num = $obj->piece_num;
1977
                $line->date_creation = $obj->date_creation;
1978
                $line->date_modification = $obj->date_modification;
1979
                if ($mode != "_tmp") {
1980
                    $line->date_export = $obj->date_export;
1981
                }
1982
                $line->date_validation = $obj->date_validation;
1983
1984
                $this->linesmvt[] = $line;
1985
            }
1986
        } else {
1987
            $this->error = "Error " . $this->db->lasterror();
1988
            dol_syslog(__METHOD__ . $this->error, LOG_ERR);
1989
            return -1;
1990
        }
1991
1992
        return 1;
1993
    }
1994
1995
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1996
    /**
1997
     * Export bookkeeping
1998
     *
1999
     * @param   string  $model  Model
2000
     * @return  int             Result
2001
     */
2002
    public function export_bookkeeping($model = 'ebp')
2003
    {
2004
		// phpcs:enable
2005
        global $conf;
2006
2007
        $sql = "SELECT rowid, doc_date, doc_type,";
2008
        $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
2009
        $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
2010
        $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,";
2011
        $sql .= " date_validated as date_validation";
2012
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2013
        $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2014
2015
        dol_syslog(get_class($this) . "::export_bookkeeping", LOG_DEBUG);
2016
2017
        $resql = $this->db->query($sql);
2018
2019
        if ($resql) {
2020
            $this->linesexport = array();
2021
2022
            $num = $this->db->num_rows($resql);
2023
            while ($obj = $this->db->fetch_object($resql)) {
2024
                $line = new BookKeepingLine($this->db);
2025
2026
                $line->id = $obj->rowid;
2027
2028
                $line->doc_date = $this->db->jdate($obj->doc_date);
2029
                $line->doc_type = $obj->doc_type;
2030
                $line->doc_ref = $obj->doc_ref;
2031
                $line->fk_doc = $obj->fk_doc;
2032
                $line->fk_docdet = $obj->fk_docdet;
2033
                $line->thirdparty_code = $obj->thirdparty_code;
2034
                $line->subledger_account = $obj->subledger_account;
2035
                $line->subledger_label = $obj->subledger_label;
2036
                $line->numero_compte = $obj->numero_compte;
2037
                $line->label_compte = $obj->label_compte;
2038
                $line->label_operation = $obj->label_operation;
2039
                $line->debit = $obj->debit;
2040
                $line->credit = $obj->credit;
2041
                $line->montant = $obj->amount;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...okKeepingLine::$montant has been deprecated: see $amount ( Ignorable by Annotation )

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

2041
                /** @scrutinizer ignore-deprecated */ $line->montant = $obj->amount;

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...
2042
                $line->amount = $obj->amount;
2043
                $line->sens = $obj->sens;
2044
                $line->code_journal = $obj->code_journal;
2045
                $line->piece_num = $obj->piece_num;
2046
                $line->date_validation = $obj->date_validation;
2047
2048
                $this->linesexport[] = $line;
2049
            }
2050
            $this->db->free($resql);
2051
2052
            return $num;
2053
        } else {
2054
            $this->error = "Error " . $this->db->lasterror();
2055
            dol_syslog(get_class($this) . "::export_bookkeeping " . $this->error, LOG_ERR);
2056
            return -1;
2057
        }
2058
    }
2059
2060
    /**
2061
     * Transform transaction
2062
     *
2063
     * @param  int      $direction      If 0: tmp => real, if 1: real => tmp
2064
     * @param  string   $piece_num      Piece num = Transaction ref
2065
     * @return int                      int Return integer <0 if KO, >0 if OK
2066
     */
2067
    public function transformTransaction($direction = 0, $piece_num = '')
2068
    {
2069
        global $conf;
2070
2071
        $error = 0;
2072
2073
        $sql_filter = $this->getCanModifyBookkeepingSQL();
2074
2075
        if (!isset($sql_filter)) {
2076
            return -1;
2077
        }
2078
2079
        $this->db->begin();
2080
2081
        if ($direction == 0) {
2082
            $next_piecenum = $this->getNextNumMvt();
2083
            $now = dol_now();
2084
2085
            if ($next_piecenum < 0) {
2086
                $error++;
2087
            }
2088
2089
            if (!$error) {
2090
                // Delete if there is an empty line
2091
                $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity) . " AND numero_compte IS NULL AND debit = 0 AND credit = 0";
2092
                $resql = $this->db->query($sql);
2093
                if (!$resql) {
2094
                    $error++;
2095
                    $this->errors[] = 'Error ' . $this->db->lasterror();
2096
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2097
                }
2098
            }
2099
2100
            if (!$error) {
2101
                $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . ' (doc_date, doc_type,';
2102
                $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2103
                $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2104
                $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num, date_creation)';
2105
                $sql .= ' SELECT doc_date, doc_type,';
2106
                $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2107
                $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2108
                $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, ' . ((int) $next_piecenum) . ", '" . $this->db->idate($now) . "'";
2109
                $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND numero_compte IS NOT NULL AND entity = ' . ((int) $conf->entity);
2110
                $sql .= $sql_filter;
2111
                $resql = $this->db->query($sql);
2112
                if (!$resql) {
2113
                    $error++;
2114
                    $this->errors[] = 'Error ' . $this->db->lasterror();
2115
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2116
                }
2117
            }
2118
2119
            if (!$error) {
2120
                $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity);
2121
                $resql = $this->db->query($sql);
2122
                if (!$resql) {
2123
                    $error++;
2124
                    $this->errors[] = 'Error ' . $this->db->lasterror();
2125
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2126
                }
2127
            }
2128
        } elseif ($direction == 1) {
2129
            if (!$error) {
2130
                $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity);
2131
                $resql = $this->db->query($sql);
2132
                if (!$resql) {
2133
                    $error++;
2134
                    $this->errors[] = 'Error ' . $this->db->lasterror();
2135
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2136
                }
2137
            }
2138
2139
            if (!$error) {
2140
                $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '_tmp (doc_date, doc_type,';
2141
                $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2142
                $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2143
                $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num)';
2144
                $sql .= ' SELECT doc_date, doc_type,';
2145
                $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2146
                $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2147
                $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num';
2148
                $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity);
2149
                $sql .= $sql_filter;
2150
                $resql = $this->db->query($sql);
2151
                if (!$resql) {
2152
                    $error++;
2153
                    $this->errors[] = 'Error ' . $this->db->lasterror();
2154
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2155
                }
2156
            }
2157
2158
            if (!$error) {
2159
                $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity);
2160
                $sql .= $sql_filter;
2161
                $resql = $this->db->query($sql);
2162
                if (!$resql) {
2163
                    $error++;
2164
                    $this->errors[] = 'Error ' . $this->db->lasterror();
2165
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2166
                }
2167
            }
2168
        }
2169
        if (!$error) {
2170
            $this->db->commit();
2171
            return 1;
2172
        } else {
2173
            $this->db->rollback();
2174
            return -1;
2175
        }
2176
        /*
2177
        $sql = "DELETE FROM ";
2178
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab";
2179
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte";
2180
        $sql .= " AND aa.active = 1";
2181
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2182
        $sql .= " AND asy.rowid = " . ((int) $pcgver);
2183
        $sql .= " AND ab.entity IN (" . getEntity('accountancy') . ")";
2184
        $sql .= " ORDER BY account_number ASC";
2185
        */
2186
    }
2187
2188
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2189
    /**
2190
     * Return list of accounts with label by chart of accounts
2191
     *
2192
     * @param string     $selectid   Preselected chart of accounts
2193
     * @param string     $htmlname  Name of field in html form
2194
     * @param int       $showempty  Add an empty field
2195
     * @param array     $event      Event options
2196
     * @param int       $select_in  Value is a aa.rowid (0 default) or aa.account_number (1)
2197
     * @param int       $select_out Set value returned by select 0=rowid (default), 1=account_number
2198
     * @param string    $aabase     Set accounting_account base class to display empty=all or from 1 to 8 will display only account beginning by this number
2199
     * @return string|int   String with HTML select or -1 if KO
2200
     */
2201
    public function select_account($selectid, $htmlname = 'account', $showempty = 0, $event = array(), $select_in = 0, $select_out = 0, $aabase = '')
2202
    {
2203
		// phpcs:enable
2204
        global $conf;
2205
2206
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/accounting.lib.php';
2207
2208
        $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2209
2210
        $sql = "SELECT DISTINCT ab.numero_compte as account_number, aa.label as label, aa.rowid as rowid, aa.fk_pcg_version";
2211
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab";
2212
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte";
2213
        $sql .= " AND aa.active = 1";
2214
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2215
        $sql .= " AND asy.rowid = " . ((int) $pcgver);
2216
        $sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2217
        $sql .= " ORDER BY account_number ASC";
2218
2219
        dol_syslog(get_class($this) . "::select_account", LOG_DEBUG);
2220
        $resql = $this->db->query($sql);
2221
2222
        if (!$resql) {
2223
            $this->error = "Error " . $this->db->lasterror();
2224
            dol_syslog(get_class($this) . "::select_account " . $this->error, LOG_ERR);
2225
            return "-1";
2226
        }
2227
2228
        $out = ajax_combobox($htmlname, $event);
2229
2230
        $options = array();
2231
        $selected = null;
2232
2233
        while ($obj = $this->db->fetch_object($resql)) {
2234
            $label = length_accountg($obj->account_number) . ' - ' . $obj->label;
2235
2236
            $select_value_in = $obj->rowid;
2237
            $select_value_out = $obj->rowid;
2238
2239
            if ($select_in == 1) {
2240
                $select_value_in = $obj->account_number;
2241
            }
2242
            if ($select_out == 1) {
2243
                $select_value_out = $obj->account_number;
2244
            }
2245
2246
            // Remember guy's we store in database llx_facturedet the rowid of accounting_account and not the account_number
2247
            // Because same account_number can be share between different accounting_system and do have the same meaning
2248
            if (($selectid != '') && $selectid == $select_value_in) {
2249
                $selected = $select_value_out;
2250
            }
2251
2252
            $options[$select_value_out] = $label;
2253
        }
2254
2255
        $out .= Form::selectarray($htmlname, $options, $selected, $showempty, 0, 0, '', 0, 0, 0, '', 'maxwidth300');
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\Form was not found. Did you mean Form? If so, make sure to prefix the type with \.
Loading history...
2256
        $this->db->free($resql);
2257
        return $out;
2258
    }
2259
2260
    /**
2261
     * Return id and description of a root accounting account.
2262
     * FIXME: This function takes the parent of parent to get the root account !
2263
     *
2264
     * @param   string  $account    Accounting account
2265
     * @return  array|int           Array with root account information (max 2 upper level), <0 if KO
2266
     */
2267
    public function getRootAccount($account = null)
2268
    {
2269
        global $conf;
2270
        $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2271
2272
        $sql  = "SELECT root.rowid, root.account_number, root.label as label,";
2273
        $sql .= " parent.rowid as parent_rowid, parent.account_number as parent_account_number, parent.label as parent_label";
2274
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as aa";
2275
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2276
        $sql .= " AND asy.rowid = " . ((int) $pcgver);
2277
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1";
2278
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1";
2279
        $sql .= " WHERE aa.account_number = '" . $this->db->escape($account) . "'";
2280
        $sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2281
2282
        dol_syslog(get_class($this) . "::select_account", LOG_DEBUG);
2283
        $resql = $this->db->query($sql);
2284
        if ($resql) {
2285
            $obj = '';
2286
            if ($this->db->num_rows($resql)) {
2287
                $obj = $this->db->fetch_object($resql);
2288
            }
2289
2290
            $result = array('id' => $obj->rowid, 'account_number' => $obj->account_number, 'label' => $obj->label);
2291
            return $result;
2292
        } else {
2293
            $this->error = "Error " . $this->db->lasterror();
2294
            dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR);
2295
2296
            return -1;
2297
        }
2298
    }
2299
2300
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2301
    /**
2302
     * Description of accounting account
2303
     *
2304
     * @param   string  $account    Accounting account
2305
     * @return  string|int              Account desc or -1 if KO
2306
     */
2307
    public function get_compte_desc($account = null)
2308
    {
2309
		// phpcs:enable
2310
        global $conf;
2311
2312
        $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2313
        $sql  = "SELECT aa.account_number, aa.label, aa.rowid, aa.fk_pcg_version, cat.label as category";
2314
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as aa ";
2315
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2316
        $sql .= " AND aa.account_number = '" . $this->db->escape($account) . "'";
2317
        $sql .= " AND asy.rowid = " . ((int) $pcgver);
2318
        $sql .= " AND aa.active = 1";
2319
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid";
2320
        $sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2321
2322
        dol_syslog(get_class($this) . "::select_account", LOG_DEBUG);
2323
        $resql = $this->db->query($sql);
2324
        if ($resql) {
2325
            $obj = '';
2326
            if ($this->db->num_rows($resql)) {
2327
                $obj = $this->db->fetch_object($resql);
2328
            }
2329
            if (empty($obj->category)) {
2330
                return $obj->label;
2331
            } else {
2332
                return $obj->label . ' (' . $obj->category . ')';
2333
            }
2334
        } else {
2335
            $this->error = "Error " . $this->db->lasterror();
2336
            dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR);
2337
            return "-1";
2338
        }
2339
    }
2340
2341
    /**
2342
     * Get SQL string for check if the bookkeeping can be modified or deleted ? (cached)
2343
     *
2344
     * @param   string      $alias      Bookkeeping alias table
2345
     * @param   bool        $force      Force reload
2346
     * @return  string|null             SQL filter or null if error
2347
     */
2348
    public function getCanModifyBookkeepingSQL($alias = '', $force = false)
2349
    {
2350
        global $conf;
2351
2352
        $alias = trim($alias);
2353
        $alias = !empty($alias) && strpos($alias, '.') < 0 ? $alias . "." : $alias;
2354
2355
        if (!isset(self::$can_modify_bookkeeping_sql_cached[$alias]) || $force) {
2356
            $result = $this->loadFiscalPeriods($force, 'active');
2357
            if ($result < 0) {
2358
                return null;
2359
            }
2360
2361
            $sql_list = array();
2362
            if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2363
                foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2364
                    $sql_list[] = "('" . $this->db->idate($fiscal_period['date_start']) . "' <= " . $this->db->sanitize($alias) . "doc_date AND " . $this->db->sanitize($alias) . "doc_date <= '" . $this->db->idate($fiscal_period['date_end']) . "')";
2365
                }
2366
            }
2367
            $sqlsanitized = implode(' OR ', $sql_list);
2368
            self::$can_modify_bookkeeping_sql_cached[$alias] = !empty($sql_list) ? " AND (" . $sqlsanitized . ")" : "";
2369
        }
2370
2371
        return self::$can_modify_bookkeeping_sql_cached[$alias];
2372
    }
2373
2374
    /**
2375
     * Is the bookkeeping can be modified or deleted ?
2376
     *
2377
     * @param   int     $id     Bookkeeping ID
2378
     * @param   string  $mode   Mode ('' or 'tmp_')
2379
     * @return  int             Return integer <0 if KO, == 0 if No, == 1 if Yes
2380
     */
2381
    public function canModifyBookkeeping($id, $mode = '')
2382
    {
2383
        global $conf;
2384
2385
        if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2386
            $result = $this->loadFiscalPeriods(false, 'closed');
2387
2388
            if ($result < 0) {
2389
                return -1;
2390
            }
2391
2392
            $bookkeeping = new BookKeeping($this->db);
2393
            $result = $bookkeeping->fetch($id, null, $mode);
2394
            if ($result <= 0) {
2395
                return $result;
2396
            }
2397
2398
            if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2399
                foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2400
                    if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2401
                        return 0;
2402
                    }
2403
                }
2404
            }
2405
2406
            return 1;
2407
        } else {
2408
            $result = $this->loadFiscalPeriods(false, 'active');
2409
            if ($result < 0) {
2410
                return -1;
2411
            }
2412
2413
            $bookkeeping = new BookKeeping($this->db);
2414
            $result = $bookkeeping->fetch($id, null, $mode);
2415
2416
            if ($result <= 0) {
2417
                return $result;
2418
            }
2419
            if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2420
                foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2421
                    if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $bookkeeping->doc_date && (empty($fiscal_period['date_end']) || $bookkeeping->doc_date <= $fiscal_period['date_end'])) {
2422
                        return 1;
2423
                    }
2424
                }
2425
            }
2426
2427
            return 0;
2428
        }
2429
    }
2430
2431
    /**
2432
     * Is the bookkeeping date valid (on an open period or not on a closed period) ?
2433
     *
2434
     * @param   int     $date       Bookkeeping date
2435
     * @return  int                 Return integer <0 if KO, == 0 if No, == 1 if date is valid for a transfer
2436
     */
2437
    public function validBookkeepingDate($date)
2438
    {
2439
        global $conf;
2440
2441
        if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2442
            $result = $this->loadFiscalPeriods(false, 'closed');
2443
2444
            if ($result < 0) {
2445
                return -1;
2446
            }
2447
2448
            if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2449
                foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2450
                    if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2451
                        return 0;
2452
                    }
2453
                }
2454
            }
2455
2456
            return 1;
2457
        } else {
2458
            $result = $this->loadFiscalPeriods(false, 'active');
2459
            if ($result < 0) {
2460
                return -1;
2461
            }
2462
2463
            if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2464
                foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2465
                    if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $date && (empty($fiscal_period['date_end']) || $date <= $fiscal_period['date_end'])) {
2466
                        return 1;
2467
                    }
2468
                }
2469
            }
2470
2471
            return 0;
2472
        }
2473
    }
2474
2475
    /**
2476
     * Load list of active fiscal period
2477
     *
2478
     * @param   bool    $force      Force reload
2479
     * @param   string  $mode       active or closed ?
2480
     * @return  int                 Return integer <0 if KO, >0 if OK
2481
     */
2482
    public function loadFiscalPeriods($force = false, $mode = 'active')
2483
    {
2484
        global $conf;
2485
2486
        if ($mode == 'active') {
2487
            if (!isset($conf->cache['active_fiscal_period_cached']) || $force) {
2488
                $sql = "SELECT date_start, date_end";
2489
                $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2490
                $sql .= " WHERE entity = " . ((int) $conf->entity);
2491
                $sql .= " AND statut = 0";
2492
2493
                $resql = $this->db->query($sql);
2494
                if (!$resql) {
2495
                    $this->errors[] = $this->db->lasterror();
2496
                    return -1;
2497
                }
2498
2499
                $list = array();
2500
                while ($obj = $this->db->fetch_object($resql)) {
2501
                    $list[] = array(
2502
                        'date_start' => $this->db->jdate($obj->date_start),
2503
                        'date_end' => $this->db->jdate($obj->date_end),
2504
                    );
2505
                }
2506
                $conf->cache['active_fiscal_period_cached'] = $list;
2507
            }
2508
        }
2509
        if ($mode == 'closed') {
2510
            if (!isset($conf->cache['closed_fiscal_period_cached']) || $force) {
2511
                $sql = "SELECT date_start, date_end";
2512
                $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2513
                $sql .= " WHERE entity = " . ((int) $conf->entity);
2514
                $sql .= " AND statut = 1";
2515
2516
                $resql = $this->db->query($sql);
2517
                if (!$resql) {
2518
                    $this->errors[] = $this->db->lasterror();
2519
                    return -1;
2520
                }
2521
2522
                $list = array();
2523
                while ($obj = $this->db->fetch_object($resql)) {
2524
                    $list[] = array(
2525
                        'date_start' => $this->db->jdate($obj->date_start),
2526
                        'date_end' => $this->db->jdate($obj->date_end),
2527
                    );
2528
                }
2529
                $conf->cache['closed_fiscal_period_cached'] = $list;
2530
            }
2531
        }
2532
2533
        return 1;
2534
    }
2535
2536
    /**
2537
     * Get list of fiscal period
2538
     *
2539
     * @param   string  $filter     Filter
2540
     * @return  array<array{id:int,label:string,date_start:string,date_end:string,status:int}>|int          Return integer <0 if KO, Fiscal periods : [[id, date_start, date_end, label], ...]
2541
     */
2542
    public function getFiscalPeriods($filter = '')
2543
    {
2544
        global $conf;
2545
        $list = array();
2546
2547
        $sql = "SELECT rowid, label, date_start, date_end, statut";
2548
        $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2549
        $sql .= " WHERE entity = " . ((int) $conf->entity);
2550
        if (!empty($filter)) {
2551
            $sql .= " AND (" . $this->db->sanitize($filter, 1, 1, 1) . ')';
2552
        }
2553
        $sql .= $this->db->order('date_start', 'ASC');
2554
2555
        $resql = $this->db->query($sql);
2556
        if (!$resql) {
2557
            $this->errors[] = $this->db->lasterror();
2558
            return -1;
2559
        }
2560
2561
        while ($obj = $this->db->fetch_object($resql)) {
2562
            $list[$obj->rowid] = array(
2563
                'id' => (int) $obj->rowid,
2564
                'label' => $obj->label,
2565
                'date_start' => $this->db->jdate($obj->date_start),
2566
                'date_end' => $this->db->jdate($obj->date_end),
2567
                'status' => (int) $obj->statut,
2568
            );
2569
        }
2570
2571
        return $list;
2572
    }
2573
2574
    /**
2575
     * Get list of count by month into the fiscal period
2576
     *
2577
     * @param   int         $date_start     Date start
2578
     * @param   int         $date_end       Date end
2579
     * @return  array|int                   Return integer <0 if KO, Fiscal periods : [[id, date_start, date_end, label], ...]
2580
     */
2581
    public function getCountByMonthForFiscalPeriod($date_start, $date_end)
2582
    {
2583
        $total = 0;
2584
        $list = array();
2585
2586
        $sql = "SELECT YEAR(b.doc_date) as year";
2587
        for ($i = 1; $i <= 12; $i++) {
2588
            $sql .= ", SUM(" . $this->db->ifsql("MONTH(b.doc_date) = " . ((int) $i), "1", "0") . ") AS month" . ((int) $i);
2589
        }
2590
        $sql .= ", COUNT(b.rowid) as total";
2591
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as b";
2592
        $sql .= " WHERE b.doc_date >= '" . $this->db->idate($date_start) . "'";
2593
        $sql .= " AND b.doc_date <= '" . $this->db->idate($date_end) . "'";
2594
        $sql .= " AND b.entity IN (" . getEntity('bookkeeping', 0) . ")"; // We don't share object for accountancy
2595
2596
        // Get count for each month into the fiscal period
2597
        if (getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) {
2598
            // TODO Analyse is done by finding record not into a closed period
2599
            // Loop on each closed period
2600
            $sql .= " AND b.doc_date BETWEEN 0 AND 0";
2601
        } else {
2602
            // Analyse closed record using the unitary flag/date on each record
2603
            $sql .= " AND date_validated IS NULL";
2604
        }
2605
2606
        $sql .= " GROUP BY YEAR(b.doc_date)";
2607
        $sql .= $this->db->order("year", 'ASC');
2608
2609
        dol_syslog(__METHOD__, LOG_DEBUG);
2610
        $resql = $this->db->query($sql);
2611
        if (!$resql) {
2612
            $this->errors[] = $this->db->lasterror();
2613
            return -1;
2614
        }
2615
2616
        while ($obj = $this->db->fetch_object($resql)) {
2617
            $total += (int) $obj->total;
2618
            $year_list = array(
2619
                'year' => (int) $obj->year,
2620
                'count' => array(),
2621
                'total' => (int) $obj->total,
2622
            );
2623
            for ($i = 1; $i <= 12; $i++) {
2624
                $year_list['count'][$i] = (int) $obj->{'month' . $i};
2625
            }
2626
2627
            $list[] = $year_list;
2628
        }
2629
2630
        $this->db->free($resql);
2631
2632
        return array(
2633
            'total' => $total,
2634
            'list' => $list,
2635
        );
2636
    }
2637
2638
    /**
2639
     *  Validate all movement between the specified dates
2640
     *
2641
     * @param   int     $date_start     Date start
2642
     * @param   int     $date_end       Date end
2643
     * @return  int                     int Return integer <0 if KO, >0 if OK
2644
     */
2645
    public function validateMovementForFiscalPeriod($date_start, $date_end)
2646
    {
2647
        global $conf;
2648
2649
        $now = dol_now();
2650
2651
        // Specify as export : update field date_validated on selected month/year
2652
        $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
2653
        $sql .= " SET date_validated = '" . $this->db->idate($now) . "'";
2654
        $sql .= " WHERE entity = " . ((int) $conf->entity);
2655
        $sql .= " AND DATE(doc_date) >= '" . $this->db->idate($date_start) . "'";
2656
        $sql .= " AND DATE(doc_date) <= '" . $this->db->idate($date_end) . "'";
2657
        $sql .= " AND date_validated IS NULL";
2658
2659
        dol_syslog(__METHOD__, LOG_DEBUG);
2660
        $resql = $this->db->query($sql);
2661
        if (!$resql) {
2662
            $this->errors[] = $this->db->lasterror();
2663
            return -1;
2664
        }
2665
2666
        return 1;
2667
    }
2668
2669
    /**
2670
     *  Define accounting result
2671
     *
2672
     * @param   int     $date_start     Date start
2673
     * @param   int     $date_end       Date end
2674
     * @return  string                  Accounting result
2675
     */
2676
    public function accountingResult($date_start, $date_end)
2677
    {
2678
        global $conf;
2679
2680
        $this->db->begin();
2681
2682
        $income_statement_amount = 0;
2683
2684
        if (getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) {
2685
            $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2686
2687
            $pcg_type_filter = array();
2688
            foreach ($accounting_groups_used_for_income_statement as $item) {
2689
                $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2690
            }
2691
2692
            $sql = 'SELECT';
2693
            $sql .= " t.numero_compte,";
2694
            $sql .= " aa.pcg_type,";
2695
            $sql .= " (SUM(t.credit) - SUM(t.debit)) as accounting_result";
2696
            $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2697
            $sql .= ' LEFT JOIN  ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2698
            $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2699
            $sql .= " AND aa.entity = " . ((int) $conf->entity);
2700
            $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')';
2701
            $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2702
            $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
2703
            $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
2704
            $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2705
2706
            $resql = $this->db->query($sql);
2707
            if (!$resql) {
2708
                $this->errors[] = 'Error ' . $this->db->lasterror();
2709
                dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2710
            } else {
2711
                while ($obj = $this->db->fetch_object($resql)) {
2712
                    $income_statement_amount += $obj->accounting_result;
2713
                }
2714
            }
2715
        }
2716
2717
        return (string) $income_statement_amount;
2718
    }
2719
2720
    /**
2721
     *  Close fiscal period
2722
     *
2723
     * @param   int     $fiscal_period_id               Fiscal year ID
2724
     * @param   int     $new_fiscal_period_id           New fiscal year ID
2725
     * @param   bool    $separate_auxiliary_account     Separate auxiliary account
2726
     * @param   bool    $generate_bookkeeping_records   Generate closure bookkeeping records
2727
     * @return  int                                     int Return integer <0 if KO, >0 if OK
2728
     */
2729
    public function closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account = false, $generate_bookkeeping_records = true)
2730
    {
2731
        global $conf, $langs, $user;
2732
2733
        // Current fiscal period
2734
        $fiscal_period_id = max(0, $fiscal_period_id);
2735
        if (empty($fiscal_period_id)) {
2736
            $langs->load('errors');
2737
            $this->errors[] = $langs->trans('ErrorBadParameters');
2738
            return -1;
2739
        }
2740
        $fiscal_period = new Fiscalyear($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\Fiscalyear was not found. Did you mean Fiscalyear? If so, make sure to prefix the type with \.
Loading history...
2741
        $result = $fiscal_period->fetch($fiscal_period_id);
2742
        if ($result < 0) {
2743
            $this->error = $fiscal_period->error;
2744
            $this->errors = $fiscal_period->errors;
2745
            return -1;
2746
        } elseif (empty($fiscal_period->id)) {
2747
            $langs->loadLangs(array('errors', 'compta'));
2748
            $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2749
            return -1;
2750
        }
2751
2752
        // New fiscal period
2753
        $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2754
        if (empty($new_fiscal_period_id)) {
2755
            $langs->load('errors');
2756
            $this->errors[] = $langs->trans('ErrorBadParameters');
2757
            return -1;
2758
        }
2759
        $new_fiscal_period = new Fiscalyear($this->db);
2760
        $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2761
        if ($result < 0) {
2762
            $this->error = $new_fiscal_period->error;
2763
            $this->errors = $new_fiscal_period->errors;
2764
            return -1;
2765
        } elseif (empty($new_fiscal_period->id)) {
2766
            $langs->loadLangs(array('errors', 'compta'));
2767
            $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2768
            return -1;
2769
        }
2770
2771
        $error = 0;
2772
        $this->db->begin();
2773
2774
        $fiscal_period->statut = Fiscalyear::STATUS_CLOSED;
2775
        $fiscal_period->status = Fiscalyear::STATUS_CLOSED; // Actually not used
2776
        $result = $fiscal_period->update($user);
2777
        if ($result < 0) {
2778
            $this->error = $fiscal_period->error;
2779
            $this->errors = $fiscal_period->errors;
2780
            $error++;
2781
        }
2782
2783
        if (!$error && !empty($generate_bookkeeping_records)) {
2784
            $journal_id = max(0, getDolGlobalString('ACCOUNTING_CLOSURE_DEFAULT_JOURNAL'));
2785
            if (empty($journal_id)) {
2786
                $langs->loadLangs(array('errors', 'accountancy'));
2787
                $this->errors[] = $langs->trans('ErrorBadParameters') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2788
                $error++;
2789
            }
2790
2791
            // Fetch journal
2792
            if (!$error) {
2793
                $journal = new AccountingJournal($this->db);
2794
                $result = $journal->fetch($journal_id);
2795
                if ($result < 0) {
2796
                    $this->error = $journal->error;
2797
                    $this->errors = $journal->errors;
2798
                    $error++;
2799
                } elseif ($result == 0) {
2800
                    $langs->loadLangs(array('errors', 'accountancy'));
2801
                    $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2802
                    $error++;
2803
                }
2804
            }
2805
2806
            if (!$error) {
2807
                $accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen');
2808
                $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2809
2810
                $pcg_type_filter = array();
2811
                $tmp = array_merge($accounting_groups_used_for_balance_sheet_account, $accounting_groups_used_for_income_statement);
2812
                foreach ($tmp as $item) {
2813
                    $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2814
                }
2815
2816
                $sql = 'SELECT';
2817
                $sql .= " t.numero_compte,";
2818
                $sql .= " t.label_compte,";
2819
                if ($separate_auxiliary_account) {
2820
                    $sql .= " t.subledger_account,";
2821
                    $sql .= " t.subledger_label,";
2822
                }
2823
                $sql .= " aa.pcg_type,";
2824
                $sql .= " (SUM(t.credit) - SUM(t.debit)) as opening_balance";
2825
                $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2826
                $sql .= ' LEFT JOIN  ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2827
                $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2828
                $sql .= " AND aa.entity = " . ((int) $conf->entity);
2829
                $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')';
2830
                $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2831
                $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2832
                $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2833
                $sql .= ' GROUP BY t.numero_compte, t.label_compte, aa.pcg_type';
2834
                if ($separate_auxiliary_account) {
2835
                    $sql .= ' ,t.subledger_account, t.subledger_label';
2836
                }
2837
                $sql .= $this->db->order("t.numero_compte", "ASC");
2838
2839
                $resql = $this->db->query($sql);
2840
                if (!$resql) {
2841
                    $this->errors[] = 'Error ' . $this->db->lasterror();
2842
                    dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2843
2844
                    $error++;
2845
                } else {
2846
                    $now = dol_now();
2847
                    $income_statement_amount = 0;
2848
                    while ($obj = $this->db->fetch_object($resql)) {
2849
                        if (in_array($obj->pcg_type, $accounting_groups_used_for_income_statement)) {
2850
                            $income_statement_amount += $obj->opening_balance;
2851
                        } else {
2852
                            // Insert bookkeeping record for balance sheet account
2853
                            $mt = $obj->opening_balance;
2854
2855
                            $bookkeeping = new BookKeeping($this->db);
2856
                            $bookkeeping->doc_date = $new_fiscal_period->date_start;
2857
                            $bookkeeping->date_lim_reglement = 0;
2858
                            $bookkeeping->doc_ref = $new_fiscal_period->label;
2859
                            $bookkeeping->date_creation = $now;
2860
                            $bookkeeping->doc_type = 'closure';
2861
                            $bookkeeping->fk_doc = $new_fiscal_period->id;
2862
                            $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2863
                            $bookkeeping->thirdparty_code = '';
2864
2865
                            if ($separate_auxiliary_account) {
2866
                                $bookkeeping->subledger_account = $obj->subledger_account;
2867
                                $bookkeeping->subledger_label = $obj->subledger_label;
2868
                            } else {
2869
                                $bookkeeping->subledger_account = '';
2870
                                $bookkeeping->subledger_label = '';
2871
                            }
2872
2873
                            $bookkeeping->numero_compte = $obj->numero_compte;
2874
                            $bookkeeping->label_compte = $obj->label_compte;
2875
2876
                            $bookkeeping->label_operation = $new_fiscal_period->label;
2877
                            $bookkeeping->montant = $mt;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...s\BookKeeping::$montant has been deprecated: No more used (we have info into debit/credit and sens) ( Ignorable by Annotation )

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

2877
                            /** @scrutinizer ignore-deprecated */ $bookkeeping->montant = $mt;

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...
2878
                            $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2879
                            $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2880
                            $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2881
                            $bookkeeping->code_journal = $journal->code;
2882
                            $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2883
                            $bookkeeping->fk_user_author = $user->id;
2884
                            $bookkeeping->entity = $conf->entity;
2885
2886
                            $result = $bookkeeping->create($user);
2887
                            if ($result < 0) {
2888
                                $this->error = $bookkeeping->error;
2889
                                $this->errors = $bookkeeping->errors;
2890
                                $error++;
2891
                                break;
2892
                            }
2893
                        }
2894
                    }
2895
2896
                    // Insert bookkeeping record for income statement
2897
                    if (!$error && $income_statement_amount != 0) {
2898
                        $mt = $income_statement_amount;
2899
                        $accountingaccount = new AccountingAccount($this->db);
2900
                        $accountingaccount->fetch(null, getDolGlobalString($income_statement_amount < 0 ? 'ACCOUNTING_RESULT_LOSS' : 'ACCOUNTING_RESULT_PROFIT'), true);
2901
2902
                        $bookkeeping = new BookKeeping($this->db);
2903
                        $bookkeeping->doc_date = $new_fiscal_period->date_start;
2904
                        $bookkeeping->date_lim_reglement = 0;
2905
                        $bookkeeping->doc_ref = $new_fiscal_period->label;
2906
                        $bookkeeping->date_creation = $now;
2907
                        $bookkeeping->doc_type = 'closure';
2908
                        $bookkeeping->fk_doc = $new_fiscal_period->id;
2909
                        $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2910
                        $bookkeeping->thirdparty_code = '';
2911
2912
                        if ($separate_auxiliary_account) {
2913
                            $bookkeeping->subledger_label = '';
2914
                            $bookkeeping->subledger_account = $obj->subledger_account;
2915
                            $bookkeeping->subledger_label = $obj->subledger_label;
2916
                        } else {
2917
                            $bookkeeping->subledger_account = '';
2918
                            $bookkeeping->subledger_label = '';
2919
                        }
2920
2921
                        $bookkeeping->numero_compte = $accountingaccount->account_number;
2922
                        $bookkeeping->label_compte = $accountingaccount->label;
2923
2924
                        $bookkeeping->label_operation = $new_fiscal_period->label;
2925
                        $bookkeeping->montant = $mt;
2926
                        $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2927
                        $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2928
                        $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2929
                        $bookkeeping->code_journal = $journal->code;
2930
                        $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2931
                        $bookkeeping->fk_user_author = $user->id;
2932
                        $bookkeeping->entity = $conf->entity;
2933
2934
                        $result = $bookkeeping->create($user);
2935
                        if ($result < 0) {
2936
                            $this->error = $bookkeeping->error;
2937
                            $this->errors = $bookkeeping->errors;
2938
                            $error++;
2939
                        }
2940
                    }
2941
                    $this->db->free($resql);
2942
                }
2943
            }
2944
        }
2945
2946
        if ($error) {
2947
            $this->db->rollback();
2948
            return -1;
2949
        } else {
2950
            $this->db->commit();
2951
            return 1;
2952
        }
2953
    }
2954
2955
    /**
2956
     *  Insert accounting reversal into the inventory journal of the new fiscal period
2957
     *
2958
     * @param   int     $fiscal_period_id       Fiscal year ID
2959
     * @param   int     $inventory_journal_id   Inventory journal ID
2960
     * @param   int     $new_fiscal_period_id   New fiscal year ID
2961
     * @param   int     $date_start             Date start
2962
     * @param   int     $date_end               Date end
2963
     * @return  int                             int Return integer <0 if KO, >0 if OK
2964
     */
2965
    public function insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end)
2966
    {
2967
        global $conf, $langs, $user;
2968
2969
        // Current fiscal period
2970
        $fiscal_period_id = max(0, $fiscal_period_id);
2971
        if (empty($fiscal_period_id)) {
2972
            $langs->load('errors');
2973
            $this->errors[] = $langs->trans('ErrorBadParameters');
2974
            return -1;
2975
        }
2976
        $fiscal_period = new Fiscalyear($this->db);
2977
        $result = $fiscal_period->fetch($fiscal_period_id);
2978
        if ($result < 0) {
2979
            $this->error = $fiscal_period->error;
2980
            $this->errors = $fiscal_period->errors;
2981
            return -1;
2982
        } elseif (empty($fiscal_period->id)) {
2983
            $langs->loadLangs(array('errors', 'compta'));
2984
            $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2985
            return -1;
2986
        }
2987
2988
        // New fiscal period
2989
        $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2990
        if (empty($new_fiscal_period_id)) {
2991
            $langs->load('errors');
2992
            $this->errors[] = $langs->trans('ErrorBadParameters');
2993
            return -1;
2994
        }
2995
        $new_fiscal_period = new Fiscalyear($this->db);
2996
        $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2997
        if ($result < 0) {
2998
            $this->error = $new_fiscal_period->error;
2999
            $this->errors = $new_fiscal_period->errors;
3000
            return -1;
3001
        } elseif (empty($new_fiscal_period->id)) {
3002
            $langs->loadLangs(array('errors', 'compta'));
3003
            $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
3004
            return -1;
3005
        }
3006
3007
        // Inventory journal
3008
        $inventory_journal_id = max(0, $inventory_journal_id);
3009
        if (empty($inventory_journal_id)) {
3010
            $langs->load('errors');
3011
            $this->errors[] = $langs->trans('ErrorBadParameters');
3012
            return -1;
3013
        }
3014
        // Fetch journal
3015
        $inventory_journal = new AccountingJournal($this->db);
3016
        $result = $inventory_journal->fetch($inventory_journal_id);
3017
        if ($result < 0) {
3018
            $this->error = $inventory_journal->error;
3019
            $this->errors = $inventory_journal->errors;
3020
            return -1;
3021
        } elseif ($result == 0) {
3022
            $langs->loadLangs(array('errors', 'accountancy'));
3023
            $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('InventoryJournal');
3024
            return -1;
3025
        }
3026
3027
        $error = 0;
3028
        $this->db->begin();
3029
3030
        $sql = 'SELECT t.rowid';
3031
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
3032
        $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
3033
        $sql .= " AND code_journal = '" . $this->db->escape($inventory_journal->code) . "'";
3034
        $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
3035
        $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
3036
        $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
3037
        $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
3038
3039
        $resql = $this->db->query($sql);
3040
        if (!$resql) {
3041
            $this->errors[] = 'Error ' . $this->db->lasterror();
3042
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
3043
3044
            $error++;
3045
        } else {
3046
            $now = dol_now();
3047
            while ($obj = $this->db->fetch_object($resql)) {
3048
                $bookkeeping = new BookKeeping($this->db);
3049
                $result = $bookkeeping->fetch($obj->rowid);
3050
                if ($result < 0) {
3051
                    $this->error = $inventory_journal->error;
3052
                    $this->errors = $inventory_journal->errors;
3053
                    $error++;
3054
                    break;
3055
                } elseif ($result == 0) {
3056
                    $langs->loadLangs(array('errors', 'accountancy'));
3057
                    $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('LineId') . ': ' . $obj->rowid;
3058
                    $error++;
3059
                    break;
3060
                }
3061
3062
                $bookkeeping->id = 0;
3063
                $bookkeeping->doc_date = $new_fiscal_period->date_start;
3064
                $bookkeeping->doc_ref = $new_fiscal_period->label;
3065
                $bookkeeping->date_creation = $now;
3066
                $bookkeeping->doc_type = 'accounting_reversal';
3067
                $bookkeeping->fk_doc = $new_fiscal_period->id;
3068
                $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
3069
3070
                $bookkeeping->montant = -$bookkeeping->montant;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...s\BookKeeping::$montant has been deprecated: No more used (we have info into debit/credit and sens) ( Ignorable by Annotation )

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

3070
                $bookkeeping->montant = -/** @scrutinizer ignore-deprecated */ $bookkeeping->montant;

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...
3071
                $bookkeeping->sens = ($bookkeeping->montant >= 0) ? 'C' : 'D';
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...s\BookKeeping::$montant has been deprecated: No more used (we have info into debit/credit and sens) ( Ignorable by Annotation )

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

3071
                $bookkeeping->sens = (/** @scrutinizer ignore-deprecated */ $bookkeeping->montant >= 0) ? 'C' : 'D';

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...
3072
                $old_debit = $bookkeeping->debit;
3073
                $bookkeeping->debit = $bookkeeping->credit;
3074
                $bookkeeping->credit = $old_debit;
3075
3076
                $bookkeeping->fk_user_author = $user->id;
3077
                $bookkeeping->entity = $conf->entity;
3078
3079
                $result = $bookkeeping->create($user);
3080
                if ($result < 0) {
3081
                    $this->error = $bookkeeping->error;
3082
                    $this->errors = $bookkeeping->errors;
3083
                    $error++;
3084
                    break;
3085
                }
3086
            }
3087
            $this->db->free($resql);
3088
        }
3089
3090
        if ($error) {
3091
            $this->db->rollback();
3092
            return -1;
3093
        } else {
3094
            $this->db->commit();
3095
            return 1;
3096
        }
3097
    }
3098
}
3099