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

AccountingAccount   F

Complexity

Total Complexity 184

Size/Duplication

Total Lines 907
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 482
dl 0
loc 907
rs 2
c 0
b 0
f 0
wmc 184

13 Methods

Rating   Name   Duplication   Size   Complexity  
A accountActivate() 0 23 3
F create() 0 92 20
C update() 0 37 10
A accountDeactivate() 0 29 4
A __construct() 0 6 1
A checkUsage() 0 25 3
F getNomUrl() 0 97 32
B fetch() 0 61 9
A getLibStatut() 0 3 1
B delete() 0 35 7
F getAccountingCodeToBind() 0 206 87
A info() 0 23 3
A LibStatut() 0 18 4

How to fix   Complexity   

Complex Class

Complex classes like AccountingAccount 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 AccountingAccount, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* Copyright (C) 2013-2014  Olivier Geffroy             <[email protected]>
4
 * Copyright (C) 2013-2024  Alexandre Spangaro          <[email protected]>
5
 * Copyright (C) 2013-2021  Florian Henry               <[email protected]>
6
 * Copyright (C) 2014       Juanjo Menent               <[email protected]>
7
 * Copyright (C) 2015       Ari Elbaz (elarifr)         <[email protected]>
8
 * Copyright (C) 2018-2024  Frédéric France             <[email protected]>
9
 * Copyright (C) 2024		MDW							<[email protected]>
10
 * Copyright (C) 2024       Rafael San José             <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24
 */
25
26
namespace Dolibarr\Code\Accountancy\Classes;
27
28
use Dolibarr\Core\Base\CommonObject;
29
30
/**
31
 *  \file       htdocs/accountancy/class/accountingaccount.class.php
32
 *  \ingroup    Accountancy (Double entries)
33
 *  \brief      File of class to manage accounting accounts
34
 */
35
36
require_once constant('DOL_DOCUMENT_ROOT') . '/product/class/product.class.php';
37
require_once constant('DOL_DOCUMENT_ROOT') . '/societe/class/societe.class.php';
38
require_once constant('DOL_DOCUMENT_ROOT') . '/compta/facture/class/facture.class.php';
39
40
/**
41
 * Class to manage accounting accounts
42
 */
43
class AccountingAccount extends CommonObject
44
{
45
    /**
46
     * @var string Name of element
47
     */
48
    public $element = 'accounting_account';
49
50
    /**
51
     * @var string Name of table without prefix where object is stored
52
     */
53
    public $table_element = 'accounting_account';
54
55
    /**
56
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
57
     */
58
    public $picto = 'billr';
59
60
    /**
61
     * 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user
62
     * @var integer
63
     */
64
    public $restrictiononfksoc = 1;
65
66
    /**
67
     * @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...
68
     */
69
    public $db;
70
71
    /**
72
     * @var int ID
73
     */
74
    public $id;
75
76
    /**
77
     * @var int ID
78
     */
79
    public $rowid;
80
81
    /**
82
     * Date creation record (datec)
83
     *
84
     * @var integer
85
     */
86
    public $datec;
87
88
    /**
89
     * @var string pcg version
90
     */
91
    public $fk_pcg_version;
92
93
    /**
94
     * @var string pcg type
95
     */
96
    public $pcg_type;
97
98
    /**
99
     * @var string account number
100
     */
101
    public $account_number;
102
103
    /**
104
     * @var int ID parent account
105
     */
106
    public $account_parent;
107
108
    /**
109
     * @var int ID category account
110
     */
111
    public $account_category;
112
113
    /**
114
     * @var int Label category account
115
     */
116
    public $account_category_label;
117
118
    /**
119
     * @var int Status
120
     */
121
    public $status;
122
123
    /**
124
     * @var string Label of account
125
     */
126
    public $label;
127
128
    /**
129
     * @var string Label short of account
130
     */
131
    public $labelshort;
132
133
    /**
134
     * @var int ID
135
     */
136
    public $fk_user_author;
137
138
    /**
139
     * @var int ID
140
     */
141
    public $fk_user_modif;
142
143
    /**
144
     * @var int active (duplicate with status)
145
     */
146
    public $active;
147
148
    /**
149
     * @var int reconcilable
150
     */
151
    public $reconcilable;
152
153
    /**
154
     * @var array cache array
155
     */
156
    private $accountingaccount_codetotid_cache = array();
157
158
159
    const STATUS_ENABLED = 1;
160
    const STATUS_DISABLED = 0;
161
162
163
    /**
164
     * Constructor
165
     *
166
     * @param DoliDB $db Database handle
167
     */
168
    public function __construct($db)
169
    {
170
        $this->db = $db;
171
172
        $this->ismultientitymanaged = 1;
173
        $this->next_prev_filter = "fk_pcg_version IN (SELECT pcg_version FROM " . MAIN_DB_PREFIX . "accounting_system WHERE rowid = " . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ")"; // Used to add a filter in Form::showrefnav method
174
    }
175
176
    /**
177
     * Load record in memory
178
     *
179
     * @param   int             $rowid                      Id
180
     * @param   string|null     $account_number             Account number
181
     * @param   int|boolean     $limittocurrentchart        1 or true=Load record only if it is into current active chart of account
182
     * @param   string          $limittoachartaccount       'ABC'=Load record only if it is into chart account with code 'ABC' (better and faster than previous parameter if you have chart of account code).
183
     * @return  int                                         Return integer <0 if KO, 0 if not found, Id of record if OK and found
184
     */
185
    public function fetch($rowid = 0, $account_number = null, $limittocurrentchart = 0, $limittoachartaccount = '')
186
    {
187
        global $conf;
188
189
        if ($rowid || $account_number) {
190
            $sql  = "SELECT a.rowid as rowid, a.datec, a.tms, a.fk_pcg_version, a.pcg_type, a.account_number, a.account_parent, a.label, a.labelshort, a.fk_accounting_category, a.fk_user_author, a.fk_user_modif, a.active, a.reconcilable";
191
            $sql .= ", ca.label as category_label";
192
            $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as a";
193
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_accounting_category as ca ON a.fk_accounting_category = ca.rowid";
194
            $sql .= " WHERE";
195
            if ($rowid) {
196
                $sql .= " a.rowid = " . (int) $rowid;
197
            } elseif ($account_number) {
198
                $sql .= " a.account_number = '" . $this->db->escape($account_number) . "'";
199
                $sql .= " AND a.entity = " . $conf->entity;
200
            }
201
            if (!empty($limittocurrentchart)) {
202
                $sql .= ' AND a.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')';
203
            }
204
            if (!empty($limittoachartaccount)) {
205
                $sql .= " AND a.fk_pcg_version = '" . $this->db->escape($limittoachartaccount) . "'";
206
            }
207
208
            dol_syslog(get_class($this) . "::fetch rowid=" . $rowid . " account_number=" . $account_number, LOG_DEBUG);
209
210
            $result = $this->db->query($sql);
211
            if ($result) {
212
                $obj = $this->db->fetch_object($result);
213
214
                if ($obj) {
215
                    $this->id = $obj->rowid;
216
                    $this->rowid = $obj->rowid;
217
                    $this->ref = $obj->account_number;
218
                    $this->datec = $this->db->jdate($obj->datec);
219
                    $this->date_creation = $this->db->jdate($obj->datec);
220
                    $this->date_modification = $this->db->jdate($obj->tms);
221
                    //$this->tms = $this->datem;
222
                    $this->fk_pcg_version = $obj->fk_pcg_version;
223
                    $this->pcg_type = $obj->pcg_type;
224
                    $this->account_number = $obj->account_number;
225
                    $this->account_parent = $obj->account_parent;
226
                    $this->label = $obj->label;
227
                    $this->labelshort = $obj->labelshort;
228
                    $this->account_category = $obj->fk_accounting_category;
229
                    $this->account_category_label = $obj->category_label;
230
                    $this->fk_user_author = $obj->fk_user_author;
231
                    $this->fk_user_modif = $obj->fk_user_modif;
232
                    $this->active = $obj->active;
233
                    $this->status = $obj->active;
234
                    $this->reconcilable = $obj->reconcilable;
235
236
                    return $this->id;
237
                } else {
238
                    return 0;
239
                }
240
            } else {
241
                $this->error = "Error " . $this->db->lasterror();
242
                $this->errors[] = "Error " . $this->db->lasterror();
243
            }
244
        }
245
        return -1;
246
    }
247
248
    /**
249
     * Insert new accounting account in chart of accounts
250
     *
251
     * @param User $user User making action
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...
252
     * @param int $notrigger Disable triggers
253
     * @return int                 Return integer <0 if KO, >0 if OK
254
     */
255
    public function create($user, $notrigger = 0)
256
    {
257
        global $conf;
258
        $error = 0;
259
        $now = dol_now();
260
261
        // Clean parameters
262
        if (isset($this->fk_pcg_version)) {
263
            $this->fk_pcg_version = trim($this->fk_pcg_version);
264
        }
265
        if (isset($this->pcg_type)) {
266
            $this->pcg_type = trim($this->pcg_type);
267
        }
268
        if (isset($this->account_number)) {
269
            $this->account_number = trim($this->account_number);
270
        }
271
        if (isset($this->label)) {
272
            $this->label = trim($this->label);
273
        }
274
        if (isset($this->labelshort)) {
275
            $this->labelshort = trim($this->labelshort);
276
        }
277
278
        if (empty($this->pcg_type) || $this->pcg_type == '-1') {
279
            $this->pcg_type = 'XXXXXX';
280
        }
281
        // Check parameters
282
        // Put here code to add control on parameters values
283
284
        // Insert request
285
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "accounting_account(";
286
        $sql .= "datec";
287
        $sql .= ", entity";
288
        $sql .= ", fk_pcg_version";
289
        $sql .= ", pcg_type";
290
        $sql .= ", account_number";
291
        $sql .= ", account_parent";
292
        $sql .= ", label";
293
        $sql .= ", labelshort";
294
        $sql .= ", fk_accounting_category";
295
        $sql .= ", fk_user_author";
296
        $sql .= ", active";
297
        $sql .= ", reconcilable";
298
        $sql .= ") VALUES (";
299
        $sql .= " '" . $this->db->idate($now) . "'";
300
        $sql .= ", " . ((int) $conf->entity);
301
        $sql .= ", " . (empty($this->fk_pcg_version) ? 'NULL' : "'" . $this->db->escape($this->fk_pcg_version) . "'");
302
        $sql .= ", " . (empty($this->pcg_type) ? 'NULL' : "'" . $this->db->escape($this->pcg_type) . "'");
303
        $sql .= ", " . (empty($this->account_number) ? 'NULL' : "'" . $this->db->escape($this->account_number) . "'");
304
        $sql .= ", " . (empty($this->account_parent) ? 0 : (int) $this->account_parent);
305
        $sql .= ", " . (empty($this->label) ? "''" : "'" . $this->db->escape($this->label) . "'");
306
        $sql .= ", " . (empty($this->labelshort) ? "''" : "'" . $this->db->escape($this->labelshort) . "'");
307
        $sql .= ", " . (empty($this->account_category) ? 0 : (int) $this->account_category);
308
        $sql .= ", " . ((int) $user->id);
309
        $sql .= ", " . (int) $this->active;
310
        $sql .= ", " . (int) $this->reconcilable;
311
        $sql .= ")";
312
313
        $this->db->begin();
314
315
        dol_syslog(get_class($this) . "::create", LOG_DEBUG);
316
        $resql = $this->db->query($sql);
317
        if (!$resql) {
318
            $error++;
319
            $this->errors[] = "Error " . $this->db->lasterror();
320
        }
321
322
        if (!$error) {
323
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "accounting_account");
324
325
            // Uncomment this and change MYOBJECT to your own tag if you
326
            // want this action to call a trigger.
327
            //if (! $error && ! $notrigger) {
328
329
            // // Call triggers
330
            // $result=$this->call_trigger('MYOBJECT_CREATE',$user);
331
            // if ($result < 0) $error++;
332
            // // End call triggers
333
            //}
334
        }
335
336
        // Commit or rollback
337
        if ($error) {
338
            foreach ($this->errors as $errmsg) {
339
                dol_syslog(get_class($this) . "::create " . $errmsg, LOG_ERR);
340
                $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
341
            }
342
            $this->db->rollback();
343
            return -1 * $error;
344
        } else {
345
            $this->db->commit();
346
            return $this->id;
347
        }
348
    }
349
350
    /**
351
     * Update record
352
     *
353
     * @param User $user        User making update
354
     * @return int              Return integer <0 if KO (-2 = duplicate), >0 if OK
355
     */
356
    public function update($user)
357
    {
358
        // Check parameters
359
        if (empty($this->pcg_type) || $this->pcg_type == '-1') {
360
            $this->pcg_type = 'XXXXXX';
361
        }
362
363
        $this->db->begin();
364
365
        $sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_account ";
366
        $sql .= " SET fk_pcg_version = " . ($this->fk_pcg_version ? "'" . $this->db->escape($this->fk_pcg_version) . "'" : "null");
367
        $sql .= " , pcg_type = " . ($this->pcg_type ? "'" . $this->db->escape($this->pcg_type) . "'" : "null");
368
        $sql .= " , account_number = '" . $this->db->escape($this->account_number) . "'";
369
        $sql .= " , account_parent = " . (int) $this->account_parent;
370
        $sql .= " , label = " . ($this->label ? "'" . $this->db->escape($this->label) . "'" : "''");
371
        $sql .= " , labelshort = " . ($this->labelshort ? "'" . $this->db->escape($this->labelshort) . "'" : "''");
372
        $sql .= " , fk_accounting_category = " . (empty($this->account_category) ? 0 : (int) $this->account_category);
373
        $sql .= " , fk_user_modif = " . ((int) $user->id);
374
        $sql .= " , active = " . (int) $this->active;
375
        $sql .= " , reconcilable = " . (int) $this->reconcilable;
376
        $sql .= " WHERE rowid = " . ((int) $this->id);
377
378
        dol_syslog(get_class($this) . "::update", LOG_DEBUG);
379
        $result = $this->db->query($sql);
380
        if ($result) {
381
            $this->db->commit();
382
            return 1;
383
        } else {
384
            if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
385
                $this->error = $this->db->lasterror();
386
                $this->db->rollback();
387
                return -2;
388
            }
389
390
            $this->error = $this->db->lasterror();
391
            $this->db->rollback();
392
            return -1;
393
        }
394
    }
395
396
    /**
397
     * Check usage of accounting code
398
     *
399
     * @return int Return integer <0 if KO, >0 if OK
400
     */
401
    public function checkUsage()
402
    {
403
        global $langs;
404
405
        // TODO Looks a stupid check
406
        $sql = "(SELECT fk_code_ventilation FROM " . MAIN_DB_PREFIX . "facturedet";
407
        $sql .= " WHERE fk_code_ventilation=" . ((int) $this->id) . ")";
408
        $sql .= "UNION";
409
        $sql .= " (SELECT fk_code_ventilation FROM " . MAIN_DB_PREFIX . "facture_fourn_det";
410
        $sql .= " WHERE fk_code_ventilation=" . ((int) $this->id) . ")";
411
412
        dol_syslog(get_class($this) . "::checkUsage", LOG_DEBUG);
413
        $resql = $this->db->query($sql);
414
415
        if ($resql) {
416
            $num = $this->db->num_rows($resql);
417
            if ($num > 0) {
418
                $this->error = $langs->trans('ErrorAccountancyCodeIsAlreadyUse');
419
                return 0;
420
            } else {
421
                return 1;
422
            }
423
        } else {
424
            $this->error = $this->db->lasterror();
425
            return -1;
426
        }
427
    }
428
429
    /**
430
     * Delete object in database
431
     *
432
     * @param User $user User that deletes
433
     * @param int $notrigger 0=triggers after, 1=disable triggers
434
     * @return int Return integer <0 if KO, >0 if OK
435
     */
436
    public function delete($user, $notrigger = 0)
437
    {
438
        $error = 0;
439
440
        $result = $this->checkUsage();
441
442
        if ($result > 0) {
443
            $this->db->begin();
444
445
            if (!$error) {
446
                $sql = "DELETE FROM " . MAIN_DB_PREFIX . "accounting_account";
447
                $sql .= " WHERE rowid=" . ((int) $this->id);
448
449
                dol_syslog(get_class($this) . "::delete sql=" . $sql);
450
                $resql = $this->db->query($sql);
451
                if (!$resql) {
452
                    $error++;
453
                    $this->errors[] = "Error " . $this->db->lasterror();
454
                }
455
            }
456
457
            // Commit or rollback
458
            if ($error) {
459
                foreach ($this->errors as $errmsg) {
460
                    dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR);
461
                    $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
462
                }
463
                $this->db->rollback();
464
                return -1 * $error;
465
            } else {
466
                $this->db->commit();
467
                return 1;
468
            }
469
        } else {
470
            return -1;
471
        }
472
    }
473
474
    /**
475
     * Return clicable name (with picto eventually)
476
     *
477
     * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
478
     * @param int $withlabel 0=No label, 1=Include label of account
479
     * @param int $nourl 1=Disable url
480
     * @param string $moretitle Add more text to title tooltip
481
     * @param int $notooltip 1=Disable tooltip
482
     * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
483
     * @param int $withcompletelabel 0=Short label (field short label), 1=Complete label (field label)
484
     * @param string $option 'ledger', 'journals', 'accountcard'
485
     * @return  string    String with URL
486
     */
487
    public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $withcompletelabel = 0, $option = '')
488
    {
489
        global $langs, $conf, $hookmanager;
490
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/accounting.lib.php';
491
492
        if (!empty($conf->dol_no_mouse_hover)) {
493
            $notooltip = 1; // Force disable tooltips
494
        }
495
496
        $result = '';
497
498
        $url = '';
499
        $labelurl = '';
500
        if (empty($option) || $option == 'ledger') {
501
            $url = constant('BASE_URL') . '/accountancy/bookkeeping/listbyaccount.php?search_accountancy_code_start=' . urlencode((isset($this->account_number) ? $this->account_number : '')) . '&search_accountancy_code_end=' . urlencode((isset($this->account_number) ? $this->account_number : ''));
502
            $labelurl = $langs->trans("ShowAccountingAccountInLedger");
503
        } elseif ($option == 'journals') {
504
            $url = constant('BASE_URL') . '/accountancy/bookkeeping/list.php?search_accountancy_code_start=' . urlencode($this->account_number) . '&search_accountancy_code_end=' . urlencode($this->account_number);
505
            $labelurl = $langs->trans("ShowAccountingAccountInJournals");
506
        } elseif ($option == 'accountcard') {
507
            $url = constant('BASE_URL') . '/accountancy/admin/card.php?id=' . urlencode((string) ($this->id));
508
            $labelurl = $langs->trans("ShowAccountingAccount");
509
        }
510
511
        // Add param to save lastsearch_values or not
512
        $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
513
        if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
514
            $add_save_lastsearch_values = 1;
515
        }
516
        if ($add_save_lastsearch_values) {
517
            $url .= '&save_lastsearch_values=1';
518
        }
519
520
        $picto = 'accounting_account';
521
        $label = '';
522
523
        if (empty($this->labelshort) || $withcompletelabel == 1) {
524
            $labeltoshow = $this->label;
525
        } else {
526
            $labeltoshow = $this->labelshort;
527
        }
528
529
        $label = '<u>' . $labelurl . '</u>';
530
        if (!empty($this->account_number)) {
531
            $label .= '<br><b>' . $langs->trans('AccountAccounting') . ':</b> ' . length_accountg($this->account_number);
532
        }
533
        if (!empty($labeltoshow)) {
534
            $label .= '<br><b>' . $langs->trans('Label') . ':</b> ' . $labeltoshow;
535
        }
536
        if ($moretitle) {
537
            $label .= ' - ' . $moretitle;
538
        }
539
540
        $linkclose = '';
541
        if (empty($notooltip)) {
542
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
543
                $label = $labelurl;
544
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
545
            }
546
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
547
            $linkclose .= ' class="classfortooltip"';
548
        }
549
550
        $linkstart = '<a href="' . $url . '"';
551
        $linkstart .= $linkclose . '>';
552
        $linkend = '</a>';
553
554
        if ($nourl) {
555
            $linkstart = '';
556
            $linkclose = '';
557
            $linkend = '';
558
        }
559
560
        $label_link = length_accountg($this->account_number);
561
        if ($withlabel) {
562
            $label_link .= ' - ' . ($nourl ? '<span class="opacitymedium">' : '') . $labeltoshow . ($nourl ? '</span>' : '');
563
        }
564
565
        if ($withpicto) {
566
            $result .= ($linkstart . img_object(($notooltip ? '' : $label), $picto, ($notooltip ? '' : 'class="classfortooltip"'), 0, 0, $notooltip ? 0 : 1) . $linkend);
567
        }
568
        if ($withpicto && $withpicto != 2) {
569
            $result .= ' ';
570
        }
571
        if ($withpicto != 2) {
572
            $result .= $linkstart . $label_link . $linkend;
573
        }
574
        global $action;
575
        $hookmanager->initHooks(array($this->element . 'dao'));
576
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
577
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
578
        if ($reshook > 0) {
579
            $result = $hookmanager->resPrint;
580
        } else {
581
            $result .= $hookmanager->resPrint;
582
        }
583
        return $result;
584
    }
585
586
    /**
587
     * Information on record
588
     *
589
     * @param int   $id     ID of record
590
     * @return void
591
     */
592
    public function info($id)
593
    {
594
        $sql = 'SELECT a.rowid, a.datec, a.fk_user_author, a.fk_user_modif, a.tms as date_modification';
595
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'accounting_account as a';
596
        $sql .= ' WHERE a.rowid = ' . ((int) $id);
597
598
        dol_syslog(get_class($this) . '::info sql=' . $sql);
599
        $resql = $this->db->query($sql);
600
601
        if ($resql) {
602
            if ($this->db->num_rows($resql)) {
603
                $obj = $this->db->fetch_object($resql);
604
605
                $this->id = $obj->rowid;
606
607
                $this->user_creation_id = $obj->fk_user_author;
608
                $this->user_modification_id = $obj->fk_user_modif;
609
                $this->date_creation = $this->db->jdate($obj->datec);
610
                $this->date_modification = $this->db->jdate($obj->date_modification);
611
            }
612
            $this->db->free($resql);
613
        } else {
614
            dol_print_error($this->db);
615
        }
616
    }
617
618
    /**
619
     * Deactivate an account (for status active or status reconcilable)
620
     *
621
     * @param int $id Id
622
     * @param int $mode 0=field active, 1=field reconcilable
623
     * @return int              Return integer <0 if KO, >0 if OK
624
     */
625
    public function accountDeactivate($id, $mode = 0)
626
    {
627
        $result = $this->checkUsage();
628
629
        $fieldtouse = 'active';
630
        if ($mode == 1) {
631
            $fieldtouse = 'reconcilable';
632
        }
633
634
        if ($result > 0) {
635
            $this->db->begin();
636
637
            $sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_account ";
638
            $sql .= "SET " . $this->db->sanitize($fieldtouse) . " = 0";
639
            $sql .= " WHERE rowid = " . ((int) $id);
640
641
            dol_syslog(get_class($this) . "::accountDeactivate " . $fieldtouse, LOG_DEBUG);
642
            $result = $this->db->query($sql);
643
644
            if ($result) {
645
                $this->db->commit();
646
                return 1;
647
            } else {
648
                $this->error = $this->db->lasterror();
649
                $this->db->rollback();
650
                return -1;
651
            }
652
        } else {
653
            return -1;
654
        }
655
    }
656
657
658
    /**
659
     * Account activated
660
     *
661
     * @param int $id Id
662
     * @param int $mode 0=field active, 1=field reconcilable
663
     * @return int              Return integer <0 if KO, >0 if OK
664
     */
665
    public function accountActivate($id, $mode = 0)
666
    {
667
        // phpcs:enable
668
        $this->db->begin();
669
670
        $fieldtouse = 'active';
671
        if ($mode == 1) {
672
            $fieldtouse = 'reconcilable';
673
        }
674
675
        $sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_account";
676
        $sql .= " SET " . $this->db->sanitize($fieldtouse) . " = 1";
677
        $sql .= " WHERE rowid = " . ((int) $id);
678
679
        dol_syslog(get_class($this) . "::account_activate " . $fieldtouse, LOG_DEBUG);
680
        $result = $this->db->query($sql);
681
        if ($result) {
682
            $this->db->commit();
683
            return 1;
684
        } else {
685
            $this->error = $this->db->lasterror();
686
            $this->db->rollback();
687
            return -1;
688
        }
689
    }
690
691
    /**
692
     *  Return the label of the status
693
     *
694
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
695
     *  @return string                 Label of status
696
     */
697
    public function getLibStatut($mode = 0)
698
    {
699
        return $this->LibStatut($this->status, $mode);
700
    }
701
702
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
703
    /**
704
     *  Return the label of a given status
705
     *
706
     *  @param  int     $status        Id status
707
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
708
     *  @return string                 Label of status
709
     */
710
    public function LibStatut($status, $mode = 0)
711
    {
712
		// phpcs:enable
713
        if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
714
            global $langs;
715
            $langs->load("users");
716
            $this->labelStatus[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
717
            $this->labelStatus[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
718
            $this->labelStatusShort[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
719
            $this->labelStatusShort[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
720
        }
721
722
        $statusType = 'status4';
723
        if ($status == self::STATUS_DISABLED) {
724
            $statusType = 'status5';
725
        }
726
727
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
728
    }
729
730
    /**
731
     * Return a suggested account (from chart of accounts) to bind
732
     *
733
     * @param   Societe                             $buyer              Object buyer
734
     * @param   Societe                             $seller             Object seller
735
     * @param   Product                             $product            Product object sell or buy
736
     * @param   Facture|FactureFournisseur          $facture            Facture
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\Facture was not found. Did you mean Facture? If so, make sure to prefix the type with \.
Loading history...
Bug introduced by
The type Dolibarr\Code\Accountanc...sses\FactureFournisseur was not found. Did you mean FactureFournisseur? If so, make sure to prefix the type with \.
Loading history...
737
     * @param   FactureLigne|SupplierInvoiceLine    $factureDet         Facture Det
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\FactureLigne was not found. Did you mean FactureLigne? If so, make sure to prefix the type with \.
Loading history...
Bug introduced by
The type Dolibarr\Code\Accountanc...ses\SupplierInvoiceLine was not found. Did you mean SupplierInvoiceLine? If so, make sure to prefix the type with \.
Loading history...
738
     * @param   array                               $accountingAccount  Array of Accounting account
739
     * @param   string                              $type               Customer / Supplier
740
     * @return  array|int                                               Array of accounting accounts suggested or < 0 if technical error.
741
     *                                                                  'suggestedaccountingaccountbydefaultfor'=>Will be used for the label to show on tooltip for account by default on any product
742
     *                                                                  'suggestedaccountingaccountfor'=>Is the account suggested for this product
743
     */
744
    public function getAccountingCodeToBind(Societe $buyer, Societe $seller, Product $product, $facture, $factureDet, $accountingAccount = array(), $type = '')
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\Product was not found. Did you mean Product? If so, make sure to prefix the type with \.
Loading history...
Bug introduced by
The type Dolibarr\Code\Accountancy\Classes\Societe was not found. Did you mean Societe? If so, make sure to prefix the type with \.
Loading history...
745
    {
746
        global $hookmanager;
747
        // Instantiate hooks for external modules
748
        $hookmanager->initHooks(array('accountancyBindingCalculation'));
749
750
        // Execute hook accountancyBindingCalculation
751
        $parameters = array('buyer' => $buyer, 'seller' => $seller, 'product' => $product, 'facture' => $facture, 'factureDet' => $factureDet ,'accountingAccount' => $accountingAccount, 0 => $type);
752
        $reshook = $hookmanager->executeHooks('accountancyBindingCalculation', $parameters); // Note that $action and $object may have been modified by some hooks
753
754
        if (empty($reshook)) {
755
            $const_name = '';
756
            if ($type == 'customer') {
757
                $const_name = "SOLD";
758
            } elseif ($type == 'supplier') {
759
                $const_name = "BUY";
760
            }
761
762
            require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/company.lib.php';
763
            $isBuyerInEEC = isInEEC($buyer);
764
            $isSellerInEEC = isInEEC($seller);
765
            $code_l = '';   // Default value for generic product/service
766
            $code_p = '';   // Value for the product/service in parameter ($product)
767
            $code_t = '';   // Default value of product account for the thirdparty
768
            $suggestedid = '';
769
770
            // Level 1 (define $code_l): Search suggested default account for product/service
771
            $suggestedaccountingaccountbydefaultfor = '';
772
            if ($factureDet->product_type == 1) {
773
                if ($buyer->country_code == $seller->country_code || empty($buyer->country_code)) {  // If buyer in same country than seller (if not defined, we assume it is same country)
774
                    $code_l = getDolGlobalString('ACCOUNTING_SERVICE_' . $const_name . '_ACCOUNT');
775
                    $suggestedaccountingaccountbydefaultfor = '';
776
                } else {
777
                    if ($isSellerInEEC && $isBuyerInEEC && $factureDet->tva_tx != 0) {    // European intravat sale, but with a VAT
778
                        $code_l = getDolGlobalString('ACCOUNTING_SERVICE_' . $const_name . '_ACCOUNT');
779
                    } elseif ($isSellerInEEC && $isBuyerInEEC && empty($buyer->tva_intra)) {    // European intravat sale, without VAT intra community number
780
                        $code_l = getDolGlobalString('ACCOUNTING_SERVICE_' . $const_name . '_ACCOUNT');
781
                        $suggestedaccountingaccountbydefaultfor = 'eecwithoutvatnumber';
782
                    } elseif ($isSellerInEEC && $isBuyerInEEC) {    // European intravat sale
783
                        $code_l = getDolGlobalString('ACCOUNTING_SERVICE_' . $const_name . '_INTRA_ACCOUNT');
784
                        $suggestedaccountingaccountbydefaultfor = 'eec';
785
                    } else {                                        // Foreign sale
786
                        $code_l = getDolGlobalString('ACCOUNTING_SERVICE_' . $const_name . '_EXPORT_ACCOUNT');
787
                        $suggestedaccountingaccountbydefaultfor = 'export';
788
                    }
789
                }
790
            } elseif ($factureDet->product_type == 0) {
791
                if ($buyer->country_code == $seller->country_code || empty($buyer->country_code)) {  // If buyer in same country than seller (if not defined, we assume it is same country)
792
                    $code_l = getDolGlobalString('ACCOUNTING_PRODUCT_' . $const_name . '_ACCOUNT');
793
                    $suggestedaccountingaccountbydefaultfor = '';
794
                } else {
795
                    if ($isSellerInEEC && $isBuyerInEEC && $factureDet->tva_tx != 0) {    // European intravat sale, but with a VAT
796
                        $code_l = getDolGlobalString('ACCOUNTING_PRODUCT_' . $const_name . '_ACCOUNT');
797
                        $suggestedaccountingaccountbydefaultfor = 'eecwithvat';
798
                    } elseif ($isSellerInEEC && $isBuyerInEEC && empty($buyer->tva_intra)) {    // European intravat sale, without VAT intra community number
799
                        $code_l = getDolGlobalString('ACCOUNTING_PRODUCT_' . $const_name . '_ACCOUNT');
800
                        $suggestedaccountingaccountbydefaultfor = 'eecwithoutvatnumber';
801
                    } elseif ($isSellerInEEC && $isBuyerInEEC) {    // European intravat sale
802
                        $code_l = getDolGlobalString('ACCOUNTING_PRODUCT_' . $const_name . '_INTRA_ACCOUNT');
803
                        $suggestedaccountingaccountbydefaultfor = 'eec';
804
                    } else {
805
                        $code_l = getDolGlobalString('ACCOUNTING_PRODUCT_' . $const_name . '_EXPORT_ACCOUNT');
806
                        $suggestedaccountingaccountbydefaultfor = 'export';
807
                    }
808
                }
809
            }
810
            if ($code_l == -1) {
811
                $code_l = '';
812
            }
813
814
            // Level 2 (define $code_p): Search suggested account for product/service (similar code exists in page index.php to make automatic binding)
815
            $suggestedaccountingaccountfor = '';
816
            if ((($buyer->country_code == $seller->country_code) || empty($buyer->country_code))) {
817
                // If buyer in same country than seller (if not defined, we assume it is same country)
818
                if ($type == 'customer' && !empty($product->accountancy_code_sell)) {
819
                    $code_p = $product->accountancy_code_sell;
820
                } elseif ($type == 'supplier' && !empty($product->accountancy_code_buy)) {
821
                    $code_p = $product->accountancy_code_buy;
822
                }
823
                $suggestedid = $accountingAccount['dom'];
824
                $suggestedaccountingaccountfor = 'prodserv';
825
            } else {
826
                if ($isSellerInEEC && $isBuyerInEEC && $factureDet->tva_tx != 0) {
827
                    // European intravat sale, but with VAT
828
                    if ($type == 'customer' && !empty($product->accountancy_code_sell)) {
829
                        $code_p = $product->accountancy_code_sell;
830
                    } elseif ($type == 'supplier' && !empty($product->accountancy_code_buy)) {
831
                        $code_p = $product->accountancy_code_buy;
832
                    }
833
                    $suggestedid = $accountingAccount['dom'];
834
                    $suggestedaccountingaccountfor = 'eecwithvat';
835
                } elseif ($isSellerInEEC && $isBuyerInEEC && empty($buyer->tva_intra)) {
836
                    // European intravat sale, without VAT intra community number
837
                    if ($type == 'customer' && !empty($product->accountancy_code_sell)) {
838
                        $code_p = $product->accountancy_code_sell;
839
                    } elseif ($type == 'supplier' && !empty($product->accountancy_code_buy)) {
840
                        $code_p = $product->accountancy_code_buy;
841
                    }
842
                    $suggestedid = $accountingAccount['dom']; // There is a doubt for this case. Is it an error on vat or we just forgot to fill vat number ?
843
                    $suggestedaccountingaccountfor = 'eecwithoutvatnumber';
844
                } elseif ($isSellerInEEC && $isBuyerInEEC && (($type == 'customer' && !empty($product->accountancy_code_sell_intra)) || ($type == 'supplier' && !empty($product->accountancy_code_buy_intra)))) {
845
                    // European intravat sale
846
                    if ($type == 'customer' && !empty($product->accountancy_code_sell_intra)) {
847
                        $code_p = $product->accountancy_code_sell_intra;
848
                    } elseif ($type == 'supplier' && !empty($product->accountancy_code_buy_intra)) {
849
                        $code_p = $product->accountancy_code_buy_intra;
850
                    }
851
                    $suggestedid = $accountingAccount['intra'];
852
                    $suggestedaccountingaccountfor = 'eec';
853
                } else {
854
                    // Foreign sale
855
                    if ($type == 'customer' && !empty($product->accountancy_code_sell_export)) {
856
                        $code_p = $product->accountancy_code_sell_export;
857
                    } elseif ($type == 'supplier' && !empty($product->accountancy_code_buy_export)) {
858
                        $code_p = $product->accountancy_code_buy_export;
859
                    }
860
                    $suggestedid = $accountingAccount['export'];
861
                    $suggestedaccountingaccountfor = 'export';
862
                }
863
            }
864
865
            // Level 3 (define $code_t): Search suggested account for this thirdparty (similar code exists in page index.php to make automatic binding)
866
            if (getDolGlobalString('ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY')) {
867
                if ($type == 'customer' && !empty($buyer->code_compta_product)) {
868
                    $code_t = $buyer->code_compta_product;
869
                    $suggestedid = $accountingAccount['thirdparty'];
870
                    $suggestedaccountingaccountfor = 'thirdparty';
871
                } elseif ($type == 'supplier' && !empty($seller->code_compta_product)) {
872
                    $code_t = $seller->code_compta_product;
873
                    $suggestedid = $accountingAccount['thirdparty'];
874
                    $suggestedaccountingaccountfor = 'thirdparty';
875
                }
876
            }
877
878
            // Manage Deposit
879
            if (getDolGlobalString('ACCOUNTING_ACCOUNT_' . strtoupper($type) . '_DEPOSIT')) {
880
                if ($factureDet->desc == "(DEPOSIT)" || $facture->type == $facture::TYPE_DEPOSIT) {
881
                    $accountdeposittoventilated = new self($this->db);
882
                    if ($type == 'customer') {
883
                        $result = $accountdeposittoventilated->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT'), 1);
884
                    } elseif ($type == 'supplier') {
885
                        $result = $accountdeposittoventilated->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT'), 1);
886
                    }
887
                    if (isset($result) && $result < 0) {
888
                        return -1;
889
                    }
890
891
                    $code_l = $accountdeposittoventilated->ref;
892
                    $code_p = '';
893
                    $code_t = '';
894
                    $suggestedid = $accountdeposittoventilated->rowid;
895
                    $suggestedaccountingaccountfor = 'deposit';
896
                }
897
898
                // For credit note invoice, if origin invoice is a deposit invoice, force also on specific customer/supplier deposit account
899
                if (!empty($facture->fk_facture_source)) {
900
                    $invoiceSource = new $facture($this->db);
901
                    $invoiceSource->fetch($facture->fk_facture_source);
902
903
                    if ($facture->type == $facture::TYPE_CREDIT_NOTE && $invoiceSource->type == $facture::TYPE_DEPOSIT) {
904
                        $accountdeposittoventilated = new self($this->db);
905
                        if ($type == 'customer') {
906
                            $accountdeposittoventilated->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT'), 1);
907
                        } elseif ($type == 'supplier') {
908
                            $accountdeposittoventilated->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT'), 1);
909
                        }
910
                        $code_l = $accountdeposittoventilated->ref;
911
                        $code_p = '';
912
                        $code_t = '';
913
                        $suggestedid = $accountdeposittoventilated->rowid;
914
                        $suggestedaccountingaccountfor = 'deposit';
915
                    }
916
                }
917
            }
918
919
            // If $suggestedid could not be guessed yet, we set it from the generic default accounting code $code_l
920
            if (empty($suggestedid) && empty($code_p) && !empty($code_l) && !getDolGlobalString('ACCOUNTANCY_DO_NOT_AUTOFILL_ACCOUNT_WITH_GENERIC')) {
921
                if (empty($this->accountingaccount_codetotid_cache[$code_l])) {
922
                    $tmpaccount = new self($this->db);
923
                    $result = $tmpaccount->fetch(0, $code_l, 1);
924
                    if ($result < 0) {
925
                        return -1;
926
                    }
927
                    if ($tmpaccount->id > 0) {
928
                        $suggestedid = $tmpaccount->id;
929
                    }
930
                    $this->accountingaccount_codetotid_cache[$code_l] = $tmpaccount->id;
931
                } else {
932
                    $suggestedid = $this->accountingaccount_codetotid_cache[$code_l];
933
                }
934
            }
935
            return array(
936
                'suggestedaccountingaccountbydefaultfor' => $suggestedaccountingaccountbydefaultfor,
937
                'suggestedaccountingaccountfor' => $suggestedaccountingaccountfor,
938
                'suggestedid' => $suggestedid,
939
                'code_l' => $code_l,
940
                'code_p' => $code_p,
941
                'code_t' => $code_t,
942
            );
943
        } else {
944
            if (is_array($hookmanager->resArray) && !empty($hookmanager->resArray)) {
945
                return $hookmanager->resArray;
946
            }
947
        }
948
949
        return -1;
950
    }
951
}
952