Test Failed
Branch main (fda838)
by Rafael
54:38 queued 11s
created

AccountingAccount::getAccountingCodeToBind()   F

Complexity

Conditions 87
Paths > 20000

Size

Total Lines 208
Code Lines 149

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 87
eloc 149
nc 427682
nop 7
dl 0
loc 208
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       Frédéric France      <[email protected]>
9
 * Copyright (C) 2024		MDW							<[email protected]>
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23
 */
24
25
namespace DoliModules\Accounting\Model;
26
27
/**
28
 *  \file       htdocs/accountancy/class/accountingaccount.class.php
29
 *  \ingroup    Accountancy (Double entries)
30
 *  \brief      File of class to manage accounting accounts
31
 */
32
33
use DoliCore\Base\GenericDocument;
34
35
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
36
require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
37
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
38
39
/**
40
 * Class to manage accounting accounts
41
 */
42
class AccountingAccount extends GenericDocument
0 ignored issues
show
Deprecated Code introduced by
The class DoliCore\Base\GenericDocument has been deprecated: This class is only needed for compatibility with Dolibarr. ( Ignorable by Annotation )

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

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