AccountingAccount::getAccountingCodeToBind()   F
last analyzed

Complexity

Conditions 87
Paths > 20000

Size

Total Lines 206
Code Lines 149

Duplication

Lines 0
Ratio 0 %

Importance

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