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

AccountancyCategory   F

Complexity

Total Complexity 124

Size/Duplication

Total Lines 867
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 465
dl 0
loc 867
rs 2
c 0
b 0
f 0
wmc 124

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
F getSumDebitCredit() 0 75 22
B getCatsCpts() 0 51 6
F create() 0 88 25
F update() 0 71 23
B getCptsCat() 0 56 8
B updateAccAcc() 0 61 9
B getCats() 0 49 6
A delete() 0 28 5
A deleteCptCat() 0 29 5
A display() 0 26 4
B fetch() 0 48 6
A getAccountsWithNoCategory() 0 33 4

How to fix   Complexity   

Complex Class

Complex classes like AccountancyCategory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AccountancyCategory, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* Copyright (C) 2016       Jamal Elbaz                 <[email protected]>
4
 * Copyright (C) 2016-2017	Alexandre Spangaro	        <[email protected]>
5
 * Copyright (C) 2018-2023  Frédéric France             <[email protected]>
6
 * Copyright (C) 2024       Rafael San José             <[email protected]>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace Dolibarr\Code\Accountancy\Classes;
23
24
/**
25
 * \file    htdocs/accountancy/class/accountancycategory.class.php
26
 * \ingroup Accountancy (Double entries)
27
 * \brief   File of class to manage categories of an accounting category_type
28
 */
29
30
// Class
31
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/accounting.lib.php';
32
33
/**
34
 * Class to manage categories of an accounting account
35
 */
36
class AccountancyCategory // extends CommonObject
37
{
38
    /**
39
     * @var DoliDB Database handler.
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
40
     */
41
    public $db;
42
43
    /**
44
     * @var string      Error string
45
     */
46
    public $error;
47
48
    /**
49
     * @var string[] Error codes (or messages)
50
     */
51
    public $errors = array();
52
53
    /**
54
     * @var string ID to identify managed object
55
     */
56
    public $element = 'c_accounting_category';
57
58
    /**
59
     * @var string Name of table without prefix where object is stored
60
     */
61
    public $table_element = 'c_accounting_category';
62
63
    /**
64
     * @var int ID
65
     * @deprecated
66
     */
67
    public $rowid;
68
69
    /**
70
     * @var int ID
71
     */
72
    public $id;
73
74
    /**
75
     * @var string Accountancy code
76
     */
77
    public $code;
78
79
    /**
80
     * @var string Accountancy Category label
81
     */
82
    public $label;
83
84
    /**
85
     * @var string Accountancy range account
86
     */
87
    public $range_account;
88
89
    /**
90
     * @var int Sens of the account:  0: credit - debit, 1: debit - credit
91
     */
92
    public $sens;
93
94
    /**
95
     * @var int Category type of accountancy
96
     */
97
    public $category_type;
98
99
    /**
100
     * @var string Formula
101
     */
102
    public $formula;
103
104
    /**
105
     * @var int     Position
106
     */
107
    public $position;
108
109
    /**
110
     * @var int country id
111
     */
112
    public $fk_country;
113
114
    /**
115
     * @var int Is active
116
     */
117
    public $active;
118
119
    /**
120
     * @var array Lines cptbk
121
     */
122
    public $lines_cptbk;
123
124
    /**
125
     * @var array Lines display
126
     */
127
    public $lines_display;
128
129
    /**
130
     * @var mixed Sum debit credit
131
     */
132
    public $sdc;
133
134
    /**
135
     * @var array Sum debit credit per month
136
     */
137
    public $sdcpermonth;
138
139
    /**
140
     * @var array Sum debit credit per account
141
     */
142
    public $sdcperaccount;
143
144
    /**
145
     *  Constructor
146
     *
147
     *  @param      DoliDB      $db      Database handler
148
     */
149
    public function __construct($db)
150
    {
151
        $this->db = $db;
152
    }
153
154
155
    /**
156
     *  Create object into database
157
     *
158
     *  @param      User    $user        User that create
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...
159
     *  @param      int     $notrigger   0=launch triggers after, 1=disable triggers
160
     *  @return     int                  Return integer <0 if KO, Id of created object if OK
161
     */
162
    public function create($user, $notrigger = 0)
163
    {
164
        global $conf, $langs;
165
        $error = 0;
166
167
        // Clean parameters
168
        if (isset($this->code)) {
169
            $this->code = trim($this->code);
170
        }
171
        if (isset($this->label)) {
172
            $this->label = trim($this->label);
173
        }
174
        if (isset($this->range_account)) {
175
            $this->range_account = trim($this->range_account);
176
        }
177
        if (isset($this->sens)) {
178
            $this->sens = (int) $this->sens;
179
        }
180
        if (isset($this->category_type)) {
181
            $this->category_type = (int) $this->category_type;
182
        }
183
        if (isset($this->formula)) {
184
            $this->formula = trim($this->formula);
185
        }
186
        if (isset($this->position)) {
187
            $this->position = (int) $this->position;
188
        }
189
        if (isset($this->fk_country)) {
190
            $this->fk_country = (int) $this->fk_country;
191
        }
192
        if (isset($this->active)) {
193
            $this->active = (int) $this->active;
194
        }
195
196
        // Check parameters
197
        // Put here code to add control on parameters values
198
199
        // Insert request
200
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "c_accounting_category(";
201
        if ($this->rowid > 0) {
202
            $sql .= "rowid, ";
203
        }
204
        $sql .= "code, ";
205
        $sql .= "label, ";
206
        $sql .= "range_account, ";
207
        $sql .= "sens, ";
208
        $sql .= "category_type, ";
209
        $sql .= "formula, ";
210
        $sql .= "position, ";
211
        $sql .= "fk_country, ";
212
        $sql .= "active, ";
213
        $sql .= "entity";
214
        $sql .= ") VALUES (";
215
        if ($this->rowid > 0) {
216
            $sql .= " " . ((int) $this->rowid) . ",";
217
        }
218
        $sql .= " " . (!isset($this->code) ? "NULL" : "'" . $this->db->escape($this->code) . "'") . ",";
219
        $sql .= " " . (!isset($this->label) ? 'NULL' : "'" . $this->db->escape($this->label) . "'") . ",";
220
        $sql .= " " . (!isset($this->range_account) ? 'NULL' : "'" . $this->db->escape($this->range_account) . "'") . ",";
221
        $sql .= " " . (!isset($this->sens) ? 'NULL' : "'" . $this->db->escape($this->sens) . "'") . ",";
222
        $sql .= " " . (!isset($this->category_type) ? 'NULL' : "'" . $this->db->escape($this->category_type) . "'") . ",";
223
        $sql .= " " . (!isset($this->formula) ? 'NULL' : "'" . $this->db->escape($this->formula) . "'") . ",";
224
        $sql .= " " . (!isset($this->position) ? 'NULL' : ((int) $this->position)) . ",";
225
        $sql .= " " . (!isset($this->fk_country) ? 'NULL' : ((int) $this->fk_country)) . ",";
226
        $sql .= " " . (!isset($this->active) ? 'NULL' : ((int) $this->active));
227
        $sql .= ", " . ((int) $conf->entity);
228
        $sql .= ")";
229
230
        $this->db->begin();
231
232
        dol_syslog(get_class($this) . "::create", LOG_DEBUG);
233
        $resql = $this->db->query($sql);
234
        if (!$resql) {
235
            $error++;
236
            $this->errors[] = "Error " . $this->db->lasterror();
237
        }
238
239
        // Commit or rollback
240
        if ($error) {
241
            foreach ($this->errors as $errmsg) {
242
                dol_syslog(get_class($this) . "::create " . $errmsg, LOG_ERR);
243
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
244
            }
245
            $this->db->rollback();
246
            return -1 * $error;
247
        } else {
248
            $this->db->commit();
249
            return $this->id;
250
        }
251
    }
252
253
254
    /**
255
     *  Load object in memory from database
256
     *
257
     *  @param      int     $id     Id object
258
     *  @param      string  $code   Code
259
     *  @param      string  $label  Label
260
     *  @return     int             Return integer <0 if KO, >0 if OK
261
     */
262
    public function fetch($id, $code = '', $label = '')
263
    {
264
        $sql = "SELECT";
265
        $sql .= " t.rowid,";
266
        $sql .= " t.code,";
267
        $sql .= " t.label,";
268
        $sql .= " t.range_account,";
269
        $sql .= " t.sens,";
270
        $sql .= " t.category_type,";
271
        $sql .= " t.formula,";
272
        $sql .= " t.position,";
273
        $sql .= " t.fk_country,";
274
        $sql .= " t.active";
275
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_accounting_category as t";
276
        if ($id) {
277
            $sql .= " WHERE t.rowid = " . ((int) $id);
278
        } else {
279
            $sql .= " WHERE t.entity IN (" . getEntity('c_accounting_category') . ")"; // Don't use entity if you use rowid
280
            if ($code) {
281
                $sql .= " AND t.code = '" . $this->db->escape($code) . "'";
282
            } elseif ($label) {
283
                $sql .= " AND t.label = '" . $this->db->escape($label) . "'";
284
            }
285
        }
286
287
        dol_syslog(get_class($this) . "::fetch", LOG_DEBUG);
288
        $resql = $this->db->query($sql);
289
        if ($resql) {
290
            if ($this->db->num_rows($resql)) {
291
                $obj = $this->db->fetch_object($resql);
292
293
                $this->id            = $obj->rowid;
294
                $this->code          = $obj->code;
295
                $this->label         = $obj->label;
296
                $this->range_account = $obj->range_account;
297
                $this->sens          = $obj->sens;
298
                $this->category_type = $obj->category_type;
299
                $this->formula       = $obj->formula;
300
                $this->position      = $obj->position;
301
                $this->fk_country    = $obj->fk_country;
302
                $this->active        = $obj->active;
303
            }
304
            $this->db->free($resql);
305
306
            return 1;
307
        } else {
308
            $this->error = "Error " . $this->db->lasterror();
309
            return -1;
310
        }
311
    }
312
313
314
    /**
315
     *  Update object into database
316
     *
317
     *  @param      User    $user        User that modify
318
     *  @param      int     $notrigger   0=launch triggers after, 1=disable triggers
319
     *  @return     int                  Return integer <0 if KO, >0 if OK
320
     */
321
    public function update($user = null, $notrigger = 0)
322
    {
323
        global $conf, $langs;
324
        $error = 0;
325
326
        // Clean parameters
327
        if (isset($this->code)) {
328
            $this->code = trim($this->code);
329
        }
330
        if (isset($this->label)) {
331
            $this->label = trim($this->label);
332
        }
333
        if (isset($this->range_account)) {
334
            $this->range_account = trim($this->range_account);
335
        }
336
        if (isset($this->sens)) {
337
            $this->sens = (int) $this->sens;
338
        }
339
        if (isset($this->category_type)) {
340
            $this->category_type = (int) $this->category_type;
341
        }
342
        if (isset($this->formula)) {
343
            $this->formula = trim($this->formula);
344
        }
345
        if (isset($this->position)) {
346
            $this->position = (int) $this->position;
347
        }
348
        if (isset($this->fk_country)) {
349
            $this->fk_country = (int) $this->fk_country;
350
        }
351
        if (isset($this->active)) {
352
            $this->active = (int) $this->active;
353
        }
354
355
356
        // Check parameters
357
        // Put here code to add control on parameters values
358
359
        // Update request
360
        $sql = "UPDATE " . MAIN_DB_PREFIX . "c_accounting_category SET";
361
        $sql .= " code=" . (isset($this->code) ? "'" . $this->db->escape($this->code) . "'" : "null") . ",";
362
        $sql .= " label=" . (isset($this->label) ? "'" . $this->db->escape($this->label) . "'" : "null") . ",";
363
        $sql .= " range_account=" . (isset($this->range_account) ? "'" . $this->db->escape($this->range_account) . "'" : "null") . ",";
364
        $sql .= " sens=" . (isset($this->sens) ? ((int) $this->sens) : "null") . ",";
365
        $sql .= " category_type=" . (isset($this->category_type) ? ((int) $this->category_type) : "null") . ",";
366
        $sql .= " formula=" . (isset($this->formula) ? "'" . $this->db->escape($this->formula) . "'" : "null") . ",";
367
        $sql .= " position=" . (isset($this->position) ? ((int) $this->position) : "null") . ",";
368
        $sql .= " fk_country=" . (isset($this->fk_country) ? ((int) $this->fk_country) : "null") . ",";
369
        $sql .= " active=" . (isset($this->active) ? ((int) $this->active) : "null");
370
        $sql .= " WHERE rowid=" . ((int) $this->id);
371
372
        $this->db->begin();
373
374
        dol_syslog(get_class($this) . "::update", LOG_DEBUG);
375
        $resql = $this->db->query($sql);
376
        if (!$resql) {
377
            $error++;
378
            $this->errors[] = "Error " . $this->db->lasterror();
379
        }
380
381
        // Commit or rollback
382
        if ($error) {
383
            foreach ($this->errors as $errmsg) {
384
                dol_syslog(get_class($this) . "::update " . $errmsg, LOG_ERR);
385
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
386
            }
387
            $this->db->rollback();
388
            return -1 * $error;
389
        } else {
390
            $this->db->commit();
391
            return 1;
392
        }
393
    }
394
395
396
    /**
397
     *  Delete object in database
398
     *
399
     *  @param  User    $user        User that delete
400
     *  @param  int     $notrigger   0=launch triggers after, 1=disable triggers
401
     *  @return int                  Return integer <0 if KO, >0 if OK
402
     */
403
    public function delete($user, $notrigger = 0)
404
    {
405
        global $conf, $langs;
406
        $error = 0;
407
408
        $sql = "DELETE FROM " . MAIN_DB_PREFIX . "c_accounting_category";
409
        $sql .= " WHERE rowid=" . ((int) $this->id);
410
411
        $this->db->begin();
412
413
        dol_syslog(get_class($this) . "::delete", LOG_DEBUG);
414
        $resql = $this->db->query($sql);
415
        if (!$resql) {
416
            $error++;
417
            $this->errors[] = "Error " . $this->db->lasterror();
418
        }
419
420
        // Commit or rollback
421
        if ($error) {
422
            foreach ($this->errors as $errmsg) {
423
                dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR);
424
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
425
            }
426
            $this->db->rollback();
427
            return -1 * $error;
428
        } else {
429
            $this->db->commit();
430
            return 1;
431
        }
432
    }
433
434
435
    /**
436
     * Function to select into ->lines_display all accounting accounts for a given custom accounting group
437
     *
438
     * @param   int     $id     Id
439
     * @return  int             Return integer <0 if KO, 0 if not found, >0 if OK
440
     */
441
    public function display($id)
442
    {
443
        global $conf;
444
        $sql = "SELECT t.rowid, t.account_number, t.label";
445
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as t";
446
        $sql .= " WHERE t.fk_accounting_category = " . ((int) $id);
447
        $sql .= " AND t.entity = " . $conf->entity;
448
449
        $this->lines_display = array();
450
451
        dol_syslog(__METHOD__, LOG_DEBUG);
452
        $resql = $this->db->query($sql);
453
        if ($resql) {
454
            $num = $this->db->num_rows($resql);
455
            if ($num) {
456
                while ($obj = $this->db->fetch_object($resql)) {
457
                    $this->lines_display[] = $obj;
458
                }
459
            }
460
            return $num;
461
        } else {
462
            $this->error = "Error " . $this->db->lasterror();
463
            $this->errors[] = $this->error;
464
            dol_syslog(__METHOD__ . " " . implode(',', $this->errors), LOG_ERR);
465
466
            return -1;
467
        }
468
    }
469
470
    /**
471
     * Function to fill ->lines_cptbk with accounting account (defined in chart of account) and not yet into a custom group
472
     *
473
     * @param   int $id     Id of category to know which account to exclude
474
     * @return  int         Return integer <0 if KO, 0 if not found, >0 if OK
475
     */
476
    public function getAccountsWithNoCategory($id)
477
    {
478
        global $conf;
479
480
        $sql = "SELECT aa.account_number as numero_compte, aa.label as label_compte";
481
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as aa";
482
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
483
        $sql .= " WHERE (aa.fk_accounting_category <> " . ((int) $id) . " OR aa.fk_accounting_category IS NULL)";
484
        $sql .= " AND asy.rowid = " . ((int) getDolGlobalInt('CHARTOFACCOUNTS'));
485
        $sql .= " AND aa.active = 1";
486
        $sql .= " AND aa.entity = " . $conf->entity;
487
        $sql .= " GROUP BY aa.account_number, aa.label";
488
        $sql .= " ORDER BY aa.account_number, aa.label";
489
490
        $this->lines_cptbk = array();
491
492
        dol_syslog(__METHOD__, LOG_DEBUG);
493
        $resql = $this->db->query($sql);
494
        if ($resql) {
495
            $num = $this->db->num_rows($resql);
496
            if ($num) {
497
                while ($obj = $this->db->fetch_object($resql)) {
498
                    $this->lines_cptbk[] = $obj;
499
                }
500
            }
501
502
            return $num;
503
        } else {
504
            $this->error = "Error " . $this->db->lasterror();
505
            $this->errors[] = $this->error;
506
            dol_syslog(__METHOD__ . " " . implode(',', $this->errors), LOG_ERR);
507
508
            return -1;
509
        }
510
    }
511
512
    /**
513
     * Function to add an accounting account in an accounting category
514
     *
515
     * @param int $id_cat Id category
516
     * @param array $cpts list of accounts array
517
     *
518
     * @return int Return integer <0 if KO, >0 if OK
519
     */
520
    public function updateAccAcc($id_cat, $cpts = array())
521
    {
522
        global $conf;
523
        $error = 0;
524
525
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/accounting.lib.php';
526
527
        $sql = "SELECT aa.rowid, aa.account_number";
528
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as aa";
529
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
530
        $sql .= " AND asy.rowid = " . ((int) getDolGlobalInt('CHARTOFACCOUNTS'));
531
        $sql .= " AND aa.active = 1";
532
        $sql .= " AND aa.entity = " . $conf->entity;
533
        $sql .= " ORDER BY LENGTH(aa.account_number) DESC;"; // LENGTH is ok with mysql and postgresql
534
535
        $this->db->begin();
536
537
        dol_syslog(__METHOD__, LOG_DEBUG);
538
        $resql = $this->db->query($sql);
539
        if (!$resql) {
540
            $error++;
541
            $this->errors[] = "Error " . $this->db->lasterror();
542
            $this->db->rollback();
543
            return -1;
544
        }
545
546
        $accountincptsadded = array();
547
        while ($obj = $this->db->fetch_object($resql)) {
548
            $account_number_formated = length_accountg($obj->account_number);
549
            if (!empty($accountincptsadded[$account_number_formated])) {
550
                continue;
551
            }
552
553
            if (array_key_exists($account_number_formated, $cpts)) {
554
                $accountincptsadded[$account_number_formated] = 1;
555
                // We found an account number that is in list $cpts of account to add
556
                $sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_account";
557
                $sql .= " SET fk_accounting_category=" . ((int) $id_cat);
558
                $sql .= " WHERE rowid=" . ((int) $obj->rowid);
559
                dol_syslog(__METHOD__, LOG_DEBUG);
560
                $resqlupdate = $this->db->query($sql);
561
                if (!$resqlupdate) {
562
                    $error++;
563
                    $this->errors[] = "Error " . $this->db->lasterror();
564
                }
565
            }
566
        }
567
568
        // Commit or rollback
569
        if ($error) {
570
            foreach ($this->errors as $errmsg) {
571
                dol_syslog(__METHOD__ . " " . $errmsg, LOG_ERR);
572
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
573
            }
574
            $this->db->rollback();
575
576
            return -1 * $error;
577
        } else {
578
            $this->db->commit();
579
580
            return 1;
581
        }
582
    }
583
584
    /**
585
     * Function to delete an accounting account from an accounting category
586
     *
587
     * @param int $cpt_id Id of accounting account
588
     *
589
     * @return int Return integer <0 if KO, >0 if OK
590
     */
591
    public function deleteCptCat($cpt_id)
592
    {
593
        $error = 0;
594
595
        $sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_account as aa";
596
        $sql .= " SET fk_accounting_category= 0";
597
        $sql .= " WHERE aa.rowid = " . ((int) $cpt_id);
598
        $this->db->begin();
599
600
        dol_syslog(__METHOD__, LOG_DEBUG);
601
        $resql = $this->db->query($sql);
602
        if (!$resql) {
603
            $error++;
604
            $this->errors[] = "Error " . $this->db->lasterror();
605
        }
606
607
        // Commit or rollback
608
        if ($error) {
609
            foreach ($this->errors as $errmsg) {
610
                dol_syslog(__METHOD__ . " " . $errmsg, LOG_ERR);
611
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
612
            }
613
            $this->db->rollback();
614
615
            return -1 * $error;
616
        } else {
617
            $this->db->commit();
618
619
            return 1;
620
        }
621
    }
622
623
    /**
624
     * Function to show result of an accounting account from the ledger with a direction and a period
625
     *
626
     * @param int|array $cpt                Accounting account or array of accounting account
627
     * @param string    $date_start         Date start
628
     * @param string    $date_end           Date end
629
     * @param int       $sens               Sens of the account:  0: credit - debit (use this by default), 1: debit - credit
630
     * @param string    $thirdparty_code    Thirdparty code
631
     * @param int       $month              Specific month - Can be empty
632
     * @param int       $year               Specific year - Can be empty
633
     * @return integer                      Return integer <0 if KO, >= 0 if OK
634
     */
635
    public function getSumDebitCredit($cpt, $date_start, $date_end, $sens, $thirdparty_code = 'nofilter', $month = 0, $year = 0)
636
    {
637
        global $conf;
638
639
        $this->sdc = 0;
640
        $this->sdcpermonth = array();
641
642
        if (is_array($cpt)) {
643
            $listofaccount = '';
644
            foreach ($cpt as $cptcursor) {
645
                if (! is_null($cptcursor)) {
646
                    if ($listofaccount) {
647
                        $listofaccount .= ",";
648
                    }
649
                    $listofaccount .= "'" . $cptcursor . "'";
650
                }
651
            }
652
            if (empty($listofaccount)) {
653
                // List of account is empty, so we do no try sql request, we can say result is empty.
654
                return 0;
655
            }
656
        }
657
658
        $sql = "SELECT SUM(t.debit) as debit, SUM(t.credit) as credit";
659
        if (is_array($cpt)) {
660
            $sql .= ", t.numero_compte as accountancy_account";
661
        }
662
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as t";
663
        //if (in_array($this->db->type, array('mysql', 'mysqli'))) $sql.=' USE INDEX idx_accounting_bookkeeping_doc_date';
664
        $sql .= " WHERE t.entity = " . ((int) $conf->entity);
665
        if (is_array($cpt)) {
666
            $sql .= " AND t.numero_compte IN (" . $this->db->sanitize($listofaccount, 1) . ")";
667
        } else {
668
            $sql .= " AND t.numero_compte = '" . $this->db->escape($cpt) . "'";
669
        }
670
        if (!empty($date_start) && !empty($date_end) && (empty($month) || empty($year))) {  // If month/year provided, it is stronger than filter date_start/date_end
671
            $sql .= " AND (t.doc_date BETWEEN '" . $this->db->idate($date_start) . "' AND '" . $this->db->idate($date_end) . "')";
672
        }
673
        if (!empty($month) && !empty($year)) {
674
            $sql .= " AND (t.doc_date BETWEEN '" . $this->db->idate(dol_get_first_day($year, $month)) . "' AND '" . $this->db->idate(dol_get_last_day($year, $month)) . "')";
675
        }
676
        if ($thirdparty_code != 'nofilter') {
677
            $sql .= " AND t.thirdparty_code = '" . $this->db->escape($thirdparty_code) . "'";
678
        }
679
        if (is_array($cpt)) {
680
            $sql .= " GROUP BY t.numero_compte";
681
        }
682
683
        $resql = $this->db->query($sql);
684
        if ($resql) {
685
            $num = $this->db->num_rows($resql);
686
            if ($num) {
687
                $i = 0;
688
                while ($i < $num) {
689
                    $obj = $this->db->fetch_object($resql);
690
                    if ($obj) {
691
                        if ($sens == 1) {
692
                            $this->sdc = $obj->debit - $obj->credit;
693
                        } else {
694
                            $this->sdc = $obj->credit - $obj->debit;
695
                        }
696
                        if (is_array($cpt)) {
697
                            $this->sdcperaccount[$obj->accountancy_account] = $this->sdc;
698
                        }
699
                    }
700
                    $i++;
701
                }
702
            }
703
704
            return $num;
705
        } else {
706
            $this->error = "Error " . $this->db->lasterror();
707
            $this->errors[] = $this->error;
708
            dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR);
709
            return -1;
710
        }
711
    }
712
713
    /**
714
     * Function to get an array of all active custom groups (llx_c_accunting_categories) with their accounts from the chart of account (ll_accounting_acount)
715
     *
716
     * @param   int             $catid      Custom group ID
717
     * @return  array|integer               Result in table (array), -1 if KO
718
     * @see getCats(), getCptsCat()
719
     */
720
    public function getCatsCpts($catid = 0)
721
    {
722
        global $mysoc, $conf;
723
724
        if (empty($mysoc->country_id)) {
725
            $this->error = "Error " . $this->db->lasterror();
726
            dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR);
727
            return -1;
728
        }
729
730
        $sql = "SELECT t.rowid, t.account_number, t.label as account_label,";
731
        $sql .= " cat.code, cat.position, cat.label as name_cat, cat.sens, cat.category_type, cat.formula";
732
        $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as t, " . MAIN_DB_PREFIX . "c_accounting_category as cat";
733
        $sql .= " WHERE t.fk_accounting_category IN (SELECT c.rowid";
734
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_accounting_category as c";
735
        $sql .= " WHERE c.active = 1";
736
        $sql .= " AND c.entity = " . $conf->entity;
737
        $sql .= " AND (c.fk_country = " . ((int) $mysoc->country_id) . " OR c.fk_country = 0)";
738
        $sql .= " AND cat.rowid = t.fk_accounting_category";
739
        $sql .= " AND t.entity = " . $conf->entity;
740
        if ($catid > 0) {
741
            $sql .= " AND cat.rowid = " . ((int) $catid);
742
        }
743
        $sql .= " ORDER BY cat.position ASC";
744
745
        $resql = $this->db->query($sql);
746
        if ($resql) {
747
            $obj = '';
748
            $num = $this->db->num_rows($resql);
749
            $data = array();
750
            if ($num) {
751
                while ($obj = $this->db->fetch_object($resql)) {
752
                    $name_cat = $obj->name_cat;
753
                    $data[$name_cat][$obj->rowid] = array(
754
                        'id' => $obj->rowid,
755
                        'code' => $obj->code,
756
                        'label' => $obj->label,
757
                        'position' => $obj->position,
758
                        'category_type' => $obj->category_type,
759
                        'formula' => $obj->formula,
760
                        'sens' => $obj->sens,
761
                        'account_number' => $obj->account_number,
762
                        'account_label' => $obj->account_label
763
                    );
764
                }
765
            }
766
            return $data;
767
        } else {
768
            $this->error = "Error " . $this->db->lasterror();
769
            dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR);
770
            return -1;
771
        }
772
    }
773
774
    /**
775
     * Return list of custom groups.
776
     * For list + detail of accounting account, see getCatsCpt()
777
     *
778
     * @param   int         $categorytype       -1=All, 0=Only non computed groups, 1=Only computed groups
779
     * @param   int         $active             1= active, 0=not active
780
     * @return  array<array{code:string,label:string,formula:string,position:string,category_type:string,sens:string,bc:string}>|int    Array of groups or -1 if error
781
     * @see getCatsCpts(), getCptsCat()
782
     */
783
    public function getCats($categorytype = -1, $active = 1)
784
    {
785
        global $conf, $mysoc;
786
787
        if (empty($mysoc->country_id)) {
788
            dol_print_error(null, 'Call to select_accounting_account with mysoc country not yet defined');
789
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
790
        }
791
792
        $sql = "SELECT c.rowid, c.code, c.label, c.formula, c.position, c.category_type, c.sens";
793
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_accounting_category as c";
794
        $sql .= " WHERE c.active = " . (int) $active;
795
        $sql .= " AND c.entity = " . $conf->entity;
796
        if ($categorytype >= 0) {
797
            $sql .= " AND c.category_type = 1";
798
        }
799
        $sql .= " AND (c.fk_country = " . ((int) $mysoc->country_id) . " OR c.fk_country = 0)";
800
        $sql .= " ORDER BY c.position ASC";
801
802
        $resql = $this->db->query($sql);
803
        if ($resql) {
804
            $i = 0;
805
            $obj = '';
806
            $num = $this->db->num_rows($resql);
807
            $data = array();
808
            if ($num) {
809
                while ($i < $num) {
810
                    $obj = $this->db->fetch_object($resql);
811
812
                    $data[] = array(
813
                            'rowid' => $obj->rowid,
814
                            'code' => $obj->code,
815
                            'label' => $obj->label,
816
                            'position' => $obj->position,
817
                            'category_type' => $obj->category_type,
818
                            'formula' => $obj->formula,
819
                            'sens' => $obj->sens,
820
                            'bc' => $obj->sens
821
                    );
822
                    $i++;
823
                }
824
            }
825
            return $data;
826
        } else {
827
            $this->error = "Error " . $this->db->lasterror();
828
            $this->errors[] = $this->error;
829
            dol_syslog(__METHOD__ . " " . implode(',', $this->errors), LOG_ERR);
830
831
            return -1;
832
        }
833
    }
834
835
836
    /**
837
     * Get all accounting account of a given custom group (or a list of custom groups).
838
     * You must choose between first parameter (personalized group) or the second (free criteria filter)
839
     *
840
     * @param   int         $cat_id                 Id if personalized accounting group/category
841
     * @param   string      $predefinedgroupwhere   Sql criteria filter to select accounting accounts. This value must be sanitized and not come from an input of a user.
842
     *                                              Example: "pcg_type = 'EXPENSE' AND fk_pcg_version = 'xx'"
843
     *                                              Example: "fk_accounting_category = 99"
844
     * @return  array|int                           Array of accounting accounts or -1 if error
845
     * @see getCats(), getCatsCpts()
846
     */
847
    public function getCptsCat($cat_id, $predefinedgroupwhere = '')
848
    {
849
        global $conf, $mysoc;
850
        $sql = '';
851
852
        if (empty($mysoc->country_id) && empty($mysoc->country_code)) {
853
            dol_print_error(null, 'Call to select_accounting_account with mysoc country not yet defined');
854
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
855
        }
856
857
        $pcgverid = getDolGlobalInt('CHARTOFACCOUNTS');
858
        $pcgvercode = dol_getIdFromCode($this->db, $pcgverid, 'accounting_system', 'rowid', 'pcg_version');
859
        if (empty($pcgvercode)) {
860
            $pcgvercode = $pcgverid;
861
        }
862
863
        if (!empty($cat_id)) {
864
            $sql = "SELECT t.rowid, t.account_number, t.label as account_label";
865
            $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as t";
866
            $sql .= " WHERE t.fk_accounting_category = " . ((int) $cat_id);
867
            $sql .= " AND t.entity = " . $conf->entity;
868
            $sql .= " AND t.active = 1";
869
            $sql .= " AND t.fk_pcg_version = '" . $this->db->escape($pcgvercode) . "'";
870
            $sql .= " ORDER BY t.account_number";
871
        } else {
872
            $sql = "SELECT t.rowid, t.account_number, t.label as account_label";
873
            $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as t";
874
            $sql .= " WHERE " . $predefinedgroupwhere;
875
            $sql .= " AND t.entity = " . $conf->entity;
876
            $sql .= ' AND t.active = 1';
877
            $sql .= " AND t.fk_pcg_version = '" . $this->db->escape($pcgvercode) . "'";
878
            $sql .= " ORDER BY t.account_number";
879
        }
880
881
        $resql = $this->db->query($sql);
882
        if ($resql) {
883
            $i = 0;
884
            $obj = '';
885
            $num = $this->db->num_rows($resql);
886
            $data = array();
887
            if ($num) {
888
                while ($obj = $this->db->fetch_object($resql)) {
889
                    $data[] = array(
890
                            'id' => $obj->rowid,
891
                            'account_number' => $obj->account_number,
892
                            'account_label' => $obj->account_label,
893
                    );
894
                    $i++;
895
                }
896
            }
897
            return $data;
898
        } else {
899
            $this->error = "Error " . $this->db->lasterror();
900
            dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR);
901
902
            return -1;
903
        }
904
    }
905
}
906