Passed
Push — dev ( f7d146...05f415 )
by Rafael
60:50
created

AccountingJournal::getNomUrl()   F

Complexity

Conditions 27
Paths > 20000

Size

Total Lines 72
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
eloc 48
nc 65280
nop 5
dl 0
loc 72
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) 2017-2022  OpenDSI                     <[email protected]>
4
 * Copyright (C) 2024		MDW							<[email protected]>
5
 * Copyright (C) 2024       Frédéric France             <[email protected]>
6
 * Copyright (C) 2024       Rafael San José             <[email protected]>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace Dolibarr\Code\Accountancy\Classes;
23
24
use Dolibarr\Code\Accountancy\Classes\AccountingAccount;
25
use Dolibarr\Code\Accountancy\Classes\BookKeeping;
26
use Dolibarr\Core\Base\CommonObject;
27
28
/**
29
 * \file        htdocs/accountancy/class/accountingjournal.class.php
30
 * \ingroup     Accountancy (Double entries)
31
 * \brief       File of class to manage accounting journals
32
 */
33
34
/**
35
 * Class to manage accounting journals
36
 */
37
class AccountingJournal extends CommonObject
38
{
39
    /**
40
     * @var string ID to identify managed object
41
     */
42
    public $element = 'accounting_journal';
43
44
    /**
45
     * @var string Name of table without prefix where object is stored
46
     */
47
    public $table_element = 'accounting_journal';
48
49
    /**
50
     * @var string Fieldname with ID of parent key if this field has a parent
51
     */
52
    public $fk_element = '';
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 = 'generic';
58
59
    /**
60
     * @var int ID
61
     */
62
    public $rowid;
63
64
    /**
65
     * @var string Accounting journal code
66
     */
67
    public $code;
68
69
    /**
70
     * @var string Accounting Journal label
71
     */
72
    public $label;
73
74
    /**
75
     * @var int 1:various operations, 2:sale, 3:purchase, 4:bank, 5:expense-report, 8:inventory, 9: has-new
76
     */
77
    public $nature;
78
79
    /**
80
     * @var int is active or not
81
     */
82
    public $active;
83
84
    /**
85
     * @var array       Accounting account cached
86
     */
87
    public static $accounting_account_cached = array();
88
89
    /**
90
     * @var array       Nature mapping
91
     */
92
    public static $nature_maps = array(
93
        1 => 'variousoperations',
94
        2 => 'sells',
95
        3 => 'purchases',
96
        4 => 'bank',
97
        5 => 'expensereports',
98
        8 => 'inventories',
99
        9 => 'hasnew',
100
    );
101
102
    /**
103
     * Constructor
104
     *
105
     * @param DoliDB $db Database handle
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...
106
     */
107
    public function __construct($db)
108
    {
109
        $this->db = $db;
110
111
        $this->ismultientitymanaged = 0;
112
    }
113
114
    /**
115
     * Load an object from database
116
     *
117
     * @param   int         $rowid          Id of record to load
118
     * @param   string|null $journal_code   Journal code
119
     * @return  int                         Return integer <0 if KO, Id of record if OK and found
120
     */
121
    public function fetch($rowid = 0, $journal_code = null)
122
    {
123
        global $conf;
124
125
        if ($rowid || $journal_code) {
126
            $sql = "SELECT rowid, code, label, nature, active";
127
            $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_journal";
128
            $sql .= " WHERE";
129
            if ($rowid) {
130
                $sql .= " rowid = " . ((int) $rowid);
131
            } elseif ($journal_code) {
132
                $sql .= " code = '" . $this->db->escape($journal_code) . "'";
133
                $sql .= " AND entity  = " . $conf->entity;
134
            }
135
136
            dol_syslog(get_only_class($this) . "::fetch", LOG_DEBUG);
137
            $result = $this->db->query($sql);
138
            if ($result) {
139
                $obj = $this->db->fetch_object($result);
140
141
                if ($obj) {
142
                    $this->id = $obj->rowid;
143
                    $this->rowid        = $obj->rowid;
144
145
                    $this->code         = $obj->code;
146
                    $this->ref          = $obj->code;
147
                    $this->label        = $obj->label;
148
                    $this->nature       = $obj->nature;
149
                    $this->active       = $obj->active;
150
151
                    return $this->id;
152
                } else {
153
                    return 0;
154
                }
155
            } else {
156
                $this->error = "Error " . $this->db->lasterror();
157
                $this->errors[] = "Error " . $this->db->lasterror();
158
            }
159
        }
160
        return -1;
161
    }
162
163
    /**
164
     * Return clickable name (with picto eventually)
165
     *
166
     * @param   int     $withpicto      0=No picto, 1=Include picto into link, 2=Only picto
167
     * @param   int     $withlabel      0=No label, 1=Include label of journal, 2=Include nature of journal
168
     * @param   int     $nourl          1=Disable url
169
     * @param   string  $moretitle      Add more text to title tooltip
170
     * @param   int     $notooltip      1=Disable tooltip
171
     * @return  string  String with URL
172
     */
173
    public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0)
174
    {
175
        global $langs, $conf, $hookmanager;
176
177
        if (!empty($conf->dol_no_mouse_hover)) {
178
            $notooltip = 1; // Force disable tooltips
179
        }
180
181
        $result = '';
182
183
        $url = constant('BASE_URL') . '/accountancy/admin/journals_list.php?id=35';
184
185
        $label = '<u>' . $langs->trans("ShowAccountingJournal") . '</u>';
186
        if (!empty($this->code)) {
187
            $label .= '<br><b>' . $langs->trans('Code') . ':</b> ' . $this->code;
188
        }
189
        if (!empty($this->label)) {
190
            $label .= '<br><b>' . $langs->trans('Label') . ':</b> ' . $langs->transnoentities($this->label);
191
        }
192
        if ($moretitle) {
193
            $label .= ' - ' . $moretitle;
194
        }
195
196
        $linkclose = '';
197
        if (empty($notooltip)) {
198
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
199
                $label = $langs->trans("ShowAccountingJournal");
200
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
201
            }
202
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
203
            $linkclose .= ' class="classfortooltip"';
204
        }
205
206
        $linkstart = '<a href="' . $url . '"';
207
        $linkstart .= $linkclose . '>';
208
        $linkend = '</a>';
209
210
        if ($nourl) {
211
            $linkstart = '';
212
            $linkclose = '';
213
            $linkend = '';
214
        }
215
216
        $label_link = $this->code;
217
        if ($withlabel == 1 && !empty($this->label)) {
218
            $label_link .= ' - ' . ($nourl ? '<span class="opacitymedium">' : '') . $langs->transnoentities($this->label) . ($nourl ? '</span>' : '');
219
        }
220
        if ($withlabel == 2 && !empty($this->nature)) {
221
            $key = $langs->trans("AccountingJournalType" . $this->nature);
222
            $transferlabel = ($this->nature && $key != "AccountingJournalType" . strtoupper($langs->trans($this->nature)) ? $key : $this->label);
223
            $label_link .= ' - ' . ($nourl ? '<span class="opacitymedium">' : '') . $transferlabel . ($nourl ? '</span>' : '');
224
        }
225
226
        $result .= $linkstart;
227
        if ($withpicto) {
228
            $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
229
        }
230
        if ($withpicto != 2) {
231
            $result .= $label_link;
232
        }
233
        $result .= $linkend;
234
235
        global $action;
236
        $hookmanager->initHooks(array('accountingjournaldao'));
237
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
238
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
239
        if ($reshook > 0) {
240
            $result = $hookmanager->resPrint;
241
        } else {
242
            $result .= $hookmanager->resPrint;
243
        }
244
        return $result;
245
    }
246
247
    /**
248
     *  Return the label of the status
249
     *
250
     *  @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
251
     *  @return string                 Label of status
252
     */
253
    public function getLibType($mode = 0)
254
    {
255
        return $this->LibType($this->nature, $mode);
256
    }
257
258
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
259
    /**
260
     *  Return type of an accounting journal
261
     *
262
     *  @param  int     $nature         Id type
263
     *  @param  int     $mode           0=label long, 1=label short
264
     *  @return string                  Label of type
265
     */
266
    public function LibType($nature, $mode = 0)
267
    {
268
		// phpcs:enable
269
        global $langs;
270
271
        $langs->loadLangs(array("accountancy"));
272
273
        if ($mode == 0) {
274
            $prefix = '';
275
            if ($nature == 9) {
276
                return $langs->trans('AccountingJournalType9');
277
            } elseif ($nature == 5) {
278
                return $langs->trans('AccountingJournalType5');
279
            } elseif ($nature == 4) {
280
                return $langs->trans('AccountingJournalType4');
281
            } elseif ($nature == 3) {
282
                return $langs->trans('AccountingJournalType3');
283
            } elseif ($nature == 2) {
284
                return $langs->trans('AccountingJournalType2');
285
            } elseif ($nature == 1) {
286
                return $langs->trans('AccountingJournalType1');
287
            }
288
        } elseif ($mode == 1) {
289
            if ($nature == 9) {
290
                return $langs->trans('AccountingJournalType9');
291
            } elseif ($nature == 5) {
292
                return $langs->trans('AccountingJournalType5');
293
            } elseif ($nature == 4) {
294
                return $langs->trans('AccountingJournalType4');
295
            } elseif ($nature == 3) {
296
                return $langs->trans('AccountingJournalType3');
297
            } elseif ($nature == 2) {
298
                return $langs->trans('AccountingJournalType2');
299
            } elseif ($nature == 1) {
300
                return $langs->trans('AccountingJournalType1');
301
            }
302
        }
303
        return "";
304
    }
305
306
307
    /**
308
     *  Get journal data
309
     *
310
     * @param   User            $user               User who get infos
311
     * @param   string          $type               Type data returned ('view', 'bookkeeping', 'csv')
312
     * @param   int             $date_start         Filter 'start date'
313
     * @param   int             $date_end           Filter 'end date'
314
     * @param   string          $in_bookkeeping     Filter 'in bookkeeping' ('already', 'notyet')
315
     * @return  array|int                           Return integer <0 if KO, >0 if OK
316
     */
317
    public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
318
    {
319
        global $hookmanager;
320
321
        // Clean parameters
322
        if (empty($type)) {
323
            $type = 'view';
324
        }
325
        if (empty($in_bookkeeping)) {
326
            $in_bookkeeping = 'notyet';
327
        }
328
329
        $data = array();
330
331
        $hookmanager->initHooks(array('accountingjournaldao'));
332
        $parameters = array('data' => &$data, 'user' => $user, 'type' => $type, 'date_start' => $date_start, 'date_end' => $date_end, 'in_bookkeeping' => $in_bookkeeping);
333
        $reshook = $hookmanager->executeHooks('getData', $parameters, $this); // Note that $action and $object may have been
334
        if ($reshook < 0) {
335
            $this->error = $hookmanager->error;
336
            $this->errors = $hookmanager->errors;
337
            return -1;
338
        } elseif (empty($reshook)) {
339
            switch ($this->nature) {
340
                case 1: // Various Journal
341
                    $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping);
342
                    break;
343
                    //              case 2: // Sells Journal
344
                    //              case 3: // Purchases Journal
345
                    //              case 4: // Bank Journal
346
                    //              case 5: // Expense reports Journal
347
                    //              case 8: // Inventory Journal
348
                    //              case 9: // hasnew Journal
349
            }
350
        }
351
352
        return $data;
353
    }
354
355
    /**
356
     *  Get asset data for various journal
357
     *
358
     * @param   User            $user               User who get infos
359
     * @param   string          $type               Type data returned ('view', 'bookkeeping', 'csv')
360
     * @param   int             $date_start         Filter 'start date'
361
     * @param   int             $date_end           Filter 'end date'
362
     * @param   string          $in_bookkeeping     Filter 'in bookkeeping' ('already', 'notyet')
363
     * @return  array|int                           Return integer <0 if KO, >0 if OK
364
     */
365
    public function getAssetData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
366
    {
367
        global $conf, $langs;
368
369
        if (!isModEnabled('asset')) {
370
            return array();
371
        }
372
373
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/accounting.lib.php';
374
375
        $langs->loadLangs(array("assets"));
376
377
        // Clean parameters
378
        if (empty($type)) {
379
            $type = 'view';
380
        }
381
        if (empty($in_bookkeeping)) {
382
            $in_bookkeeping = 'notyet';
383
        }
384
385
        $sql = "";
386
        $sql .= "SELECT ad.fk_asset AS rowid, a.ref AS asset_ref, a.label AS asset_label, a.acquisition_value_ht AS asset_acquisition_value_ht";
387
        $sql .= ", a.disposal_date AS asset_disposal_date, a.disposal_amount_ht AS asset_disposal_amount_ht, a.disposal_subject_to_vat AS asset_disposal_subject_to_vat";
388
        $sql .= ", ad.rowid AS depreciation_id, ad.depreciation_mode, ad.ref AS depreciation_ref, ad.depreciation_date, ad.depreciation_ht, ad.accountancy_code_debit, ad.accountancy_code_credit";
389
        $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
390
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
391
        $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
392
        if ($in_bookkeeping == 'already') {
393
            $sql .= " AND EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')";
394
        } elseif ($in_bookkeeping == 'notyet') {
395
            $sql .= " AND NOT EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')";
396
        }
397
        $sql .= " AND ad.ref != ''"; // not reversal lines
398
        if ($date_start && $date_end) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $date_start of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $date_end of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
399
            $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'";
400
        }
401
        // Define begin binding date
402
        if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
403
            $sql .= " AND ad.depreciation_date >= '" . $this->db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) . "'";
404
        }
405
        $sql .= " ORDER BY ad.depreciation_date";
406
407
        dol_syslog(__METHOD__, LOG_DEBUG);
408
        $resql = $this->db->query($sql);
409
        if (!$resql) {
410
            $this->errors[] = $this->db->lasterror();
411
            return -1;
412
        }
413
414
        $pre_data = array(
415
            'elements' => array(),
416
        );
417
        while ($obj = $this->db->fetch_object($resql)) {
418
            if (!isset($pre_data['elements'][$obj->rowid])) {
419
                $pre_data['elements'][$obj->rowid] = array(
420
                    'ref' => $obj->asset_ref,
421
                    'label' => $obj->asset_label,
422
                    'acquisition_value_ht' => $obj->asset_acquisition_value_ht,
423
                    'depreciation' => array(),
424
                );
425
426
                // Disposal infos
427
                if (isset($obj->asset_disposal_date)) {
428
                    $pre_data['elements'][$obj->rowid]['disposal'] = array(
429
                        'date' => $this->db->jdate($obj->asset_disposal_date),
430
                        'amount' => $obj->asset_disposal_amount_ht,
431
                        'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat),
432
                    );
433
                }
434
            }
435
436
            $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit;
437
            $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit;
438
439
            $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array(
440
                'date' => $this->db->jdate($obj->depreciation_date),
441
                'ref' => $obj->depreciation_ref,
442
                'lines' => array(
443
                    $compta_debit => -$obj->depreciation_ht,
444
                    $compta_credit => $obj->depreciation_ht,
445
                ),
446
            );
447
        }
448
449
        $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal');
450
        $journal = $this->code;
451
        $journal_label = $this->label;
452
        $journal_label_formatted = $langs->transnoentities($journal_label);
453
        $now = dol_now();
454
455
        $element_static = new Asset($this->db);
456
457
        $journal_data = array();
458
        foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) {
459
            $element_static->id = $pre_data_id;
460
            $element_static->ref = (string) $pre_data_info["ref"];
461
            $element_static->label = (string) $pre_data_info["label"];
462
            $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"];
463
            $element_link = $element_static->getNomUrl(1, 'with_label');
464
465
            $element_name_formatted_0 = dol_trunc($element_static->label, 16);
466
            $label_operation = $element_static->getNomUrl(0, 'label', 16);
467
468
            $element = array(
469
                'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1),
470
                'error' => $pre_data_info['error'],
471
                'blocks' => array(),
472
            );
473
474
            // Depreciation lines
475
            //--------------------
476
            foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) {
477
                $depreciation_ref = $line["ref"];
478
                $depreciation_date = $line["date"];
479
                $depreciation_date_formatted = dol_print_date($depreciation_date, 'day');
480
481
                // lines
482
                $blocks = array();
483
                foreach ($line['lines'] as $account => $mt) {
484
                    $account_infos = $this->getAccountingAccountInfos($account);
485
486
                    if ($type == 'view') {
487
                        $account_to_show = length_accounta($account);
488
                        if (($account_to_show == "") || $account_to_show == 'NotDefined') {
489
                            $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
490
                        }
491
492
                        $blocks[] = array(
493
                            'date' => $depreciation_date_formatted,
494
                            'piece' => $element_link,
495
                            'account_accounting' => $account_to_show,
496
                            'subledger_account' => '',
497
                            'label_operation' => $label_operation . ' - ' . $depreciation_ref,
498
                            'debit' => $mt < 0 ? price(-$mt) : '',
499
                            'credit' => $mt >= 0 ? price($mt) : '',
500
                        );
501
                    } elseif ($type == 'bookkeeping') {
502
                        if ($account_infos['found']) {
503
                            $blocks[] = array(
504
                                'doc_date' => $depreciation_date,
505
                                'date_lim_reglement' => '',
506
                                'doc_ref' => $element_static->ref,
507
                                'date_creation' => $now,
508
                                'doc_type' => 'asset',
509
                                'fk_doc' => $element_static->id,
510
                                'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add
511
                                'thirdparty_code' => '',
512
                                'subledger_account' => '',
513
                                'subledger_label' => '',
514
                                'numero_compte' => $account,
515
                                'label_compte' => $account_infos['label'],
516
                                'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref,
517
                                'montant' => $mt,
518
                                'sens' => $mt < 0 ? 'D' : 'C',
519
                                'debit' => $mt < 0 ? -$mt : 0,
520
                                'credit' => $mt >= 0 ? $mt : 0,
521
                                'code_journal' => $journal,
522
                                'journal_label' => $journal_label_formatted,
523
                                'piece_num' => '',
524
                                'import_key' => '',
525
                                'fk_user_author' => $user->id,
526
                                'entity' => $conf->entity,
527
                            );
528
                        }
529
                    } else { // $type == 'csv'
530
                        $blocks[] = array(
531
                            $depreciation_date,                                     // Date
532
                            $element_static->ref,                                   // Piece
533
                            $account_infos['code_formatted_1'],                     // AccountAccounting
534
                            $element_name_formatted_0 . ' - ' . $depreciation_ref,  // LabelOperation
535
                            $mt < 0 ? price(-$mt) : '',                             // Debit
536
                            $mt >= 0 ? price($mt) : '',                             // Credit
537
                        );
538
                    }
539
                }
540
                $element['blocks'][] = $blocks;
541
            }
542
543
            // Disposal line
544
            //--------------------
545
            if (!empty($pre_data_info['disposal'])) {
546
                $disposal_date = $pre_data_info['disposal']['date'];
547
548
                if (
549
                    (!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) &&
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (! $date_start && $date_...ING') <= $disposal_date, Probably Intended Meaning: ! $date_start && $date_e...NG') <= $disposal_date)
Loading history...
Bug Best Practice introduced by
The expression $date_start of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $date_end of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
550
                    (!getDolGlobalString('ACCOUNTING_DATE_START_BINDING') || getDolGlobalInt('ACCOUNTING_DATE_START_BINDING') <= $disposal_date)
551
                ) {
552
                    $disposal_amount = $pre_data_info['disposal']['amount'];
553
                    $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat'];
554
                    $disposal_date_formatted = dol_print_date($disposal_date, 'day');
555
                    $disposal_vat = getDolGlobalInt('ASSET_DISPOSAL_VAT') > 0 ? getDolGlobalInt('ASSET_DISPOSAL_VAT') : 20;
556
557
                    // Get accountancy codes
558
                    //---------------------------
559
                    $accountancy_codes = new AssetAccountancyCodes($this->db);
560
                    $result = $accountancy_codes->fetchAccountancyCodes($element_static->id);
561
                    if ($result < 0) {
562
                        $element['error'] = $accountancy_codes->errorsToString();
563
                    } else {
564
                        // Get last depreciation cumulative amount
565
                        $element_static->fetchDepreciationLines();
566
                        foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) {
567
                            $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key];
568
569
                            if (!isset($accountancy_codes_list['value_asset_sold'])) {
570
                                continue;
571
                            }
572
573
                            $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold'];
574
                            $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset'];
575
                            $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset'];
576
                            $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment'];
577
                            $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected'];
578
                            $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales'];
579
580
                            $last_cumulative_amount_ht = 0;
581
                            $depreciated_ids = array_keys($pre_data_info['depreciation']);
582
                            foreach ($depreciation_lines as $line) {
583
                                $last_cumulative_amount_ht = $line['cumulative_depreciation_ht'];
584
                                if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) {
585
                                    break;
586
                                }
587
                            }
588
589
                            $lines = array();
590
                            $lines[0][$accountancy_code_value_asset_sold] = -($element_static->acquisition_value_ht - $last_cumulative_amount_ht);
591
                            $lines[0][$accountancy_code_depreciation_asset] = -$last_cumulative_amount_ht;
592
                            $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht;
593
594
                            $disposal_amount_vat = $disposal_subject_to_vat ? (float) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0;
595
                            $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat);
596
                            if ($disposal_subject_to_vat) {
597
                                $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat;
598
                            }
599
                            $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount;
600
601
                            foreach ($lines as $lines_block) {
602
                                $blocks = array();
603
                                foreach ($lines_block as $account => $mt) {
604
                                    $account_infos = $this->getAccountingAccountInfos($account);
605
606
                                    if ($type == 'view') {
607
                                        $account_to_show = length_accounta($account);
608
                                        if (($account_to_show == "") || $account_to_show == 'NotDefined') {
609
                                            $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
610
                                        }
611
612
                                        $blocks[] = array(
613
                                            'date' => $disposal_date_formatted,
614
                                            'piece' => $element_link,
615
                                            'account_accounting' => $account_to_show,
616
                                            'subledger_account' => '',
617
                                            'label_operation' => $label_operation . ' - ' . $disposal_ref,
618
                                            'debit' => $mt < 0 ? price(-$mt) : '',
619
                                            'credit' => $mt >= 0 ? price($mt) : '',
620
                                        );
621
                                    } elseif ($type == 'bookkeeping') {
622
                                        if ($account_infos['found']) {
623
                                            $blocks[] = array(
624
                                                'doc_date' => $disposal_date,
625
                                                'date_lim_reglement' => '',
626
                                                'doc_ref' => $element_static->ref,
627
                                                'date_creation' => $now,
628
                                                'doc_type' => 'asset',
629
                                                'fk_doc' => $element_static->id,
630
                                                'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add
631
                                                'thirdparty_code' => '',
632
                                                'subledger_account' => '',
633
                                                'subledger_label' => '',
634
                                                'numero_compte' => $account,
635
                                                'label_compte' => $account_infos['label'],
636
                                                'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref,
637
                                                'montant' => $mt,
638
                                                'sens' => $mt < 0 ? 'D' : 'C',
639
                                                'debit' => $mt < 0 ? -$mt : 0,
640
                                                'credit' => $mt >= 0 ? $mt : 0,
641
                                                'code_journal' => $journal,
642
                                                'journal_label' => $journal_label_formatted,
643
                                                'piece_num' => '',
644
                                                'import_key' => '',
645
                                                'fk_user_author' => $user->id,
646
                                                'entity' => $conf->entity,
647
                                            );
648
                                        }
649
                                    } else { // $type == 'csv'
650
                                        $blocks[] = array(
651
                                            $disposal_date,                                    // Date
652
                                            $element_static->ref,                              // Piece
653
                                            $account_infos['code_formatted_1'],                // AccountAccounting
654
                                            $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation
655
                                            $mt < 0 ? price(-$mt) : '',                        // Debit
656
                                            $mt >= 0 ? price($mt) : '',                        // Credit
657
                                        );
658
                                    }
659
                                }
660
                                $element['blocks'][] = $blocks;
661
                            }
662
                        }
663
                    }
664
                }
665
            }
666
667
            $journal_data[(int) $pre_data_id] = $element;
668
        }
669
        unset($pre_data);
670
671
        return $journal_data;
672
    }
673
674
    /**
675
     *  Write bookkeeping
676
     *
677
     * @param   User        $user               User who write in the bookkeeping
678
     * @param   array       $journal_data       Journal data to write in the bookkeeping
679
     *                                          $journal_data = array(
680
     *                                          id_element => array(
681
     *                                          'ref' => 'ref',
682
     *                                          'error' => '',
683
     *                                          'blocks' => array(
684
     *                                          pos_block => array(
685
     *                                          num_line => array(
686
     *                                          'doc_date' => '',
687
     *                                          'date_lim_reglement' => '',
688
     *                                          'doc_ref' => '',
689
     *                                          'date_creation' => '',
690
     *                                          'doc_type' => '',
691
     *                                          'fk_doc' => '',
692
     *                                          'fk_docdet' => '',
693
     *                                          'thirdparty_code' => '',
694
     *                                          'subledger_account' => '',
695
     *                                          'subledger_label' => '',
696
     *                                          'numero_compte' => '',
697
     *                                          'label_compte' => '',
698
     *                                          'label_operation' => '',
699
     *                                          'montant' => '',
700
     *                                          'sens' => '',
701
     *                                          'debit' => '',
702
     *                                          'credit' => '',
703
     *                                          'code_journal' => '',
704
     *                                          'journal_label' => '',
705
     *                                          'piece_num' => '',
706
     *                                          'import_key' => '',
707
     *                                          'fk_user_author' => '',
708
     *                                          'entity' => '',
709
     *                                          ),
710
     *                                          ),
711
     *                                          ),
712
     *                                          ),
713
     *                                          );
714
     * @param   int     $max_nb_errors          Nb error authorized before stop the process
715
     * @return  int                             Return integer <0 if KO, >0 if OK
716
     */
717
    public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10)
718
    {
719
        global $conf, $langs, $hookmanager;
720
721
        $error = 0;
722
723
        $hookmanager->initHooks(array('accountingjournaldao'));
724
        $parameters = array('journal_data' => &$journal_data);
725
        $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been
726
        if ($reshook < 0) {
727
            $this->error = $hookmanager->error;
728
            $this->errors = $hookmanager->errors;
729
            return -1;
730
        } elseif (empty($reshook)) {
731
            // Clean parameters
732
            $journal_data = is_array($journal_data) ? $journal_data : array();
733
734
            foreach ($journal_data as $element_id => $element) {
735
                $error_for_line = 0;
736
                $total_credit = 0;
737
                $total_debit = 0;
738
739
                $this->db->begin();
740
741
                if ($element['error'] == 'somelinesarenotbound') {
742
                    $error++;
743
                    $error_for_line++;
744
                    $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
745
                }
746
747
                if (!$error_for_line) {
748
                    foreach ($element['blocks'] as $lines) {
749
                        foreach ($lines as $line) {
750
                            $bookkeeping = new BookKeeping($this->db);
751
                            $bookkeeping->doc_date = $line['doc_date'];
752
                            $bookkeeping->date_lim_reglement = $line['date_lim_reglement'];
753
                            $bookkeeping->doc_ref = $line['doc_ref'];
754
                            $bookkeeping->date_creation = $line['date_creation']; // not used
755
                            $bookkeeping->doc_type = $line['doc_type'];
756
                            $bookkeeping->fk_doc = $line['fk_doc'];
757
                            $bookkeeping->fk_docdet = $line['fk_docdet'];
758
                            $bookkeeping->thirdparty_code = $line['thirdparty_code'];
759
                            $bookkeeping->subledger_account = $line['subledger_account'];
760
                            $bookkeeping->subledger_label = $line['subledger_label'];
761
                            $bookkeeping->numero_compte = $line['numero_compte'];
762
                            $bookkeeping->label_compte = $line['label_compte'];
763
                            $bookkeeping->label_operation = $line['label_operation'];
764
                            $bookkeeping->montant = $line['montant'];
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Accountanc...s\BookKeeping::$montant has been deprecated: No more used (we have info into debit/credit and sens) ( Ignorable by Annotation )

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

764
                            /** @scrutinizer ignore-deprecated */ $bookkeeping->montant = $line['montant'];

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
765
                            $bookkeeping->sens = $line['sens'];
766
                            $bookkeeping->debit = $line['debit'];
767
                            $bookkeeping->credit = $line['credit'];
768
                            $bookkeeping->code_journal = $line['code_journal'];
769
                            $bookkeeping->journal_label = $line['journal_label'];
770
                            $bookkeeping->piece_num = $line['piece_num'];
771
                            $bookkeeping->import_key = $line['import_key'];
772
                            $bookkeeping->fk_user_author = $user->id;
773
                            $bookkeeping->entity = $conf->entity;
774
775
                            $total_debit += $bookkeeping->debit;
776
                            $total_credit += $bookkeeping->credit;
777
778
                            $result = $bookkeeping->create($user);
779
                            if ($result < 0) {
780
                                if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') {   // Already exists
781
                                    $error++;
782
                                    $error_for_line++;
783
                                    $journal_data[$element_id]['error'] = 'alreadyjournalized';
784
                                } else {
785
                                    $error++;
786
                                    $error_for_line++;
787
                                    $journal_data[$element_id]['error'] = 'other';
788
                                    $this->errors[] = $bookkeeping->errorsToString();
789
                                }
790
                            }
791
                            //
792
                            //                          if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
793
                            //                              // Set last cumulative depreciation
794
                            //                                                          //                              $asset = new Asset($this->db);
795
                            //                              $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
796
                            //                              if ($result < 0) {
797
                            //                                  $error++;
798
                            //                                  $error_for_line++;
799
                            //                                  $journal_data[$element_id]['error'] = 'other';
800
                            //                                  $this->errors[] = $asset->errorsToString();
801
                            //                              }
802
                            //                          }
803
                        }
804
805
                        if ($error_for_line) {
806
                            break;
807
                        }
808
                    }
809
                }
810
811
                // Protection against a bug on lines before
812
                if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
813
                    $error++;
814
                    $error_for_line++;
815
                    $journal_data[$element_id]['error'] = 'amountsnotbalanced';
816
                    $this->errors[] = 'Try to insert a non balanced transaction in book for ' . $element['blocks'] . '. Canceled. Surely a bug.';
817
                }
818
819
                if (!$error_for_line) {
820
                    $this->db->commit();
821
                } else {
822
                    $this->db->rollback();
823
824
                    if ($error >= $max_nb_errors) {
825
                        $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
826
                        break; // Break in the foreach
827
                    }
828
                }
829
            }
830
        }
831
832
        return $error ? -$error : 1;
833
    }
834
835
    /**
836
     *  Export journal CSV
837
     *  ISO and not UTF8 !
838
     *
839
     * @param   array           $journal_data           Journal data to write in the bookkeeping
840
     *                                                  $journal_data = array(
841
     *                                                  id_element => array(
842
     *                                                  'continue' => false,
843
     *                                                  'blocks' => array(
844
     *                                                  pos_block => array(
845
     *                                                  num_line => array(
846
     *                                                  data to write in the CSV line
847
     *                                                  ),
848
     *                                                  ),
849
     *                                                  ),
850
     *                                                  ),
851
     *                                                  );
852
     * @param   int             $search_date_end        Search date end
853
     * @param   string          $sep                    CSV separator
854
     * @return  int|string                              Return integer <0 if KO, >0 if OK
855
     */
856
    public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
857
    {
858
        global $conf, $langs, $hookmanager;
859
860
        if (empty($sep)) {
861
            $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
862
        }
863
        $out = '';
864
865
        // Hook
866
        $hookmanager->initHooks(array('accountingjournaldao'));
867
        $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
868
        $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
869
        if ($reshook < 0) {
870
            $this->error = $hookmanager->error;
871
            $this->errors = $hookmanager->errors;
872
            return -1;
873
        } elseif (empty($reshook)) {
874
            // Clean parameters
875
            $journal_data = is_array($journal_data) ? $journal_data : array();
876
877
            // CSV header line
878
            $header = array();
879
            if ($this->nature == 4) {
880
                $header = array(
881
                    $langs->transnoentitiesnoconv("BankId"),
882
                    $langs->transnoentitiesnoconv("Date"),
883
                    $langs->transnoentitiesnoconv("PaymentMode"),
884
                    $langs->transnoentitiesnoconv("AccountAccounting"),
885
                    $langs->transnoentitiesnoconv("LedgerAccount"),
886
                    $langs->transnoentitiesnoconv("SubledgerAccount"),
887
                    $langs->transnoentitiesnoconv("Label"),
888
                    $langs->transnoentitiesnoconv("AccountingDebit"),
889
                    $langs->transnoentitiesnoconv("AccountingCredit"),
890
                    $langs->transnoentitiesnoconv("Journal"),
891
                    $langs->transnoentitiesnoconv("Note"),
892
                );
893
            } elseif ($this->nature == 5) {
894
                $header = array(
895
                    $langs->transnoentitiesnoconv("Date"),
896
                    $langs->transnoentitiesnoconv("Piece"),
897
                    $langs->transnoentitiesnoconv("AccountAccounting"),
898
                    $langs->transnoentitiesnoconv("LabelOperation"),
899
                    $langs->transnoentitiesnoconv("AccountingDebit"),
900
                    $langs->transnoentitiesnoconv("AccountingCredit"),
901
                );
902
            } elseif ($this->nature == 1) {
903
                $header = array(
904
                    $langs->transnoentitiesnoconv("Date"),
905
                    $langs->transnoentitiesnoconv("Piece"),
906
                    $langs->transnoentitiesnoconv("AccountAccounting"),
907
                    $langs->transnoentitiesnoconv("LabelOperation"),
908
                    $langs->transnoentitiesnoconv("AccountingDebit"),
909
                    $langs->transnoentitiesnoconv("AccountingCredit"),
910
                );
911
            }
912
913
            if (!empty($header)) {
914
                $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
915
            }
916
            foreach ($journal_data as $element_id => $element) {
917
                foreach ($element['blocks'] as $lines) {
918
                    foreach ($lines as $line) {
919
                        $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
920
                    }
921
                }
922
            }
923
        }
924
925
        return $out;
926
    }
927
928
    /**
929
     *  Get accounting account infos
930
     *
931
     * @param string    $account    Accounting account number
932
     * @return array                Accounting account infos
933
     */
934
    public function getAccountingAccountInfos($account)
935
    {
936
        if (!isset(self::$accounting_account_cached[$account])) {
937
            require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/accounting.lib.php';
938
            $accountingaccount = new AccountingAccount($this->db);
939
            $result = $accountingaccount->fetch(null, $account, true);
940
            if ($result > 0) {
941
                self::$accounting_account_cached[$account] = array(
942
                    'found' => true,
943
                    'label' => $accountingaccount->label,
944
                    'code_formatted_1' => length_accounta(html_entity_decode($account)),
945
                    'label_formatted_1' => mb_convert_encoding(dol_trunc($accountingaccount->label, 32), 'ISO-8859-1'),
946
                    'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
947
                );
948
            } else {
949
                self::$accounting_account_cached[$account] = array(
950
                    'found' => false,
951
                    'label' => '',
952
                    'code_formatted_1' => length_accounta(html_entity_decode($account)),
953
                    'label_formatted_1' => '',
954
                    'label_formatted_2' => '',
955
                );
956
            }
957
        }
958
959
        return self::$accounting_account_cached[$account];
960
    }
961
}
962