Test Failed
Branch main (fda838)
by Rafael
50:22
created

Accountancy   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 253
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 131
dl 0
loc 253
rs 8.96
c 1
b 0
f 0
wmc 43

2 Methods

Rating   Name   Duplication   Size   Complexity  
F exportData() 0 184 42
A __construct() 0 12 1

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
3
/* Copyright (C) 2015       Jean-François Ferry     <[email protected]>
4
 * Copyright (C) 2019       Cedric Ancelin          <[email protected]>
5
 * Copyright (C) 2023       Lionel Vessiller		<[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 DoliModules\Accounting\Api;
23
24
use BookKeeping;
25
use DolibarrApi;
26
use DolibarrApiAccess;
27
use Luracast\Restler\RestException;
28
29
/**
30
 * API class for accountancy
31
 *
32
 * @access protected
33
 * @class  DolibarrApiAccess {@requires user,external}
34
 *
35
 */
36
class Accountancy extends DolibarrApi
37
{
38
    /**
39
     *
40
     * @var array $FIELDS Mandatory fields, checked when create and update object
41
     */
42
    public static $FIELDS = [];
43
44
    /**
45
     * @var BookKeeping $bookkeeping {@type BookKeeping}
46
     */
47
    public $bookkeeping;
48
49
    /**
50
     * @var AccountancyExport $accountancy_export {@type AccountancyExport}
51
     */
52
    public $accountancyexport;
53
54
    /**
55
     * Constructor
56
     */
57
    public function __construct()
58
    {
59
        global $db, $langs;
60
        $this->db = $db;
61
62
        require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
63
        require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountancyexport.class.php';
64
65
        $langs->load('accountancy');
66
67
        $this->bookkeeping = new BookKeeping($this->db);
68
        $this->accountancyexport = new AccountancyExport($this->db);
69
    }
70
71
    /**
72
     * Accountancy export data
73
     *
74
     * @param string $period                            Period : 'lastmonth', 'currentmonth', 'last3months',
75
     *                                                  'last6months', 'currentyear', 'lastyear', 'fiscalyear',
76
     *                                                  'lastfiscalyear', 'actualandlastfiscalyear' or 'custom' (see
77
     *                                                  above)
78
     * @param string $date_min                          [=''] Start date of period if 'custom' is set in period
79
     *                                                  parameter Date format is 'YYYY-MM-DD'
80
     * @param string $date_max                          [=''] End date of period if 'custom' is set in period parameter
81
     *                                                  Date format is 'YYYY-MM-DD'
82
     * @param string $format                            [=''] by default uses '1' for 'Configurable (CSV)' for format
83
     *                                                  number or '1000' for FEC or '1010' for FEC2
84
     *                                                  (see AccountancyExport class)
85
     * @param int    $lettering                         [=0] by default don't export or 1 to export lettering data
86
     *                                                  (columns 'letterring_code' and 'date_lettering' returns empty
87
     *                                                  or not)
88
     * @param int    $alreadyexport                     [=0] by default export data only if it's not yet exported or 1
89
     *                                                  already exported (always export data even if 'date_export" is
90
     *                                                  set)
91
     * @param int    $notnotifiedasexport               [=0] by default notified as exported or 1 not notified as
92
     *                                                  exported (when the export is done, notified or not the column
93
     *                                                  'date_export')
94
     *
95
     * @return  string
96
     *
97
     * @url     GET exportdata
98
     *
99
     * @throws  RestException   401     Insufficient rights
100
     * @throws  RestException   404     Accountancy export period not found
101
     * @throws  RestException   404     Accountancy export start or end date not defined
102
     * @throws  RestException   404     Accountancy export format not found
103
     * @throws  RestException   500     Error on accountancy export
104
     */
105
    public function exportData($period, $date_min = '', $date_max = '', $format = '', $lettering = 0, $alreadyexport = 0, $notnotifiedasexport = 0)
106
    {
107
        global $conf, $langs;
108
109
        // check rights
110
        if (!DolibarrApiAccess::$user->hasRight('accounting', 'mouvements', 'export')) {
111
            throw new RestException(401, 'No permission to export accounting');
112
        }
113
114
        // check parameters
115
        $period_available_list = ['lastmonth', 'currentmonth', 'last3months', 'last6months', 'currentyear', 'lastyear', 'fiscalyear', 'lastfiscalyear', 'actualandlastfiscalyear', 'custom'];
116
        if (!in_array($period, $period_available_list)) {
117
            throw new RestException(404, 'Accountancy export period not found');
118
        }
119
        if ($period == 'custom') {
120
            if ($date_min == '' && $date_max == '') {
121
                throw new RestException(404, 'Accountancy export start and end date for custom period not defined');
122
            }
123
        }
124
        if ($format == '') {
125
            $format = AccountancyExport::$EXPORT_TYPE_CONFIGURABLE; // uses default
126
        }
127
128
        // get objects
129
        $bookkeeping = $this->bookkeeping;
130
        $accountancyexport = $this->accountancyexport;
131
132
        // find export format code from format number
133
        $format_number_available_list = $accountancyexport->getType();
134
        if (is_numeric($format)) {
135
            $format_number = (int) $format;
136
        } else {
137
            $format_number = 0;
138
            $format_label_available_list = array_flip($format_number_available_list);
139
            if (isset($format_label_available_list[$format])) {
140
                $format_number = $format_label_available_list[$format];
141
            }
142
        }
143
144
        // get all format available and check if exists
145
        if (!array_key_exists($format_number, $format_number_available_list)) {
146
            throw new RestException(404, 'Accountancy export format not found');
147
        }
148
149
        $sortorder = 'ASC'; // by default
150
        $sortfield = 't.piece_num, t.rowid'; // by default
151
152
        // set filter for each period available
153
        $filter = [];
154
        $doc_date_start = null;
155
        $doc_date_end = null;
156
        $now = dol_now();
157
        $now_arr = dol_getdate($now);
158
        $now_month = $now_arr['mon'];
159
        $now_year = $now_arr['year'];
160
        if ($period == 'custom') {
161
            if ($date_min != '') {
162
                $time_min = strtotime($date_min);
163
                if ($time_min !== false) {
164
                    $doc_date_start = $time_min;
165
                }
166
            }
167
            if ($date_max != '') {
168
                $time_max = strtotime($date_max);
169
                if ($time_max !== false) {
170
                    $doc_date_end = $time_max;
171
                }
172
            }
173
        } elseif ($period == 'lastmonth') {
174
            $prev_date_arr = dol_get_prev_month($now_month, $now_year); // get previous month and year if month is january
175
            $doc_date_start = dol_mktime(0, 0, 0, $prev_date_arr['month'], 1, $prev_date_arr['year']); // first day of previous month
176
            $doc_date_end = dol_get_last_day($prev_date_arr['year'], $prev_date_arr['month']); // last day of previous month
177
        } elseif ($period == 'currentmonth') {
178
            $doc_date_start = dol_mktime(0, 0, 0, $now_month, 1, $now_year); // first day of current month
179
            $doc_date_end = dol_get_last_day($now_year, $now_month); // last day of current month
180
        } elseif ($period == 'last3months' || $period == 'last6months') {
181
            if ($period == 'last3months') {
182
                // last 3 months
183
                $nb_prev_month = 3;
184
            } else {
185
                // last 6 months
186
                $nb_prev_month = 6;
187
            }
188
            $prev_month_date_list = [];
189
            $prev_month_date_list[] = dol_get_prev_month($now_month, $now_year); // get previous month for index = 0
190
            for ($i = 1; $i < $nb_prev_month; $i++) {
191
                $prev_month_date_list[] = dol_get_prev_month($prev_month_date_list[$i - 1]['month'], $prev_month_date_list[$i - 1]['year']); // get i+1 previous month for index=i
192
            }
193
            $doc_date_start = dol_mktime(0, 0, 0, $prev_month_date_list[$nb_prev_month - 1]['month'], 1, $prev_month_date_list[$nb_prev_month - 1]['year']); // first day of n previous month for index=n-1
194
            $doc_date_end = dol_get_last_day($prev_month_date_list[0]['year'], $prev_month_date_list[0]['month']); // last day of previous month for index = 0
195
        } elseif ($period == 'currentyear' || $period == 'lastyear') {
196
            $period_year = $now_year;
197
            if ($period == 'lastyear') {
198
                $period_year--;
199
            }
200
            $doc_date_start = dol_mktime(0, 0, 0, 1, 1, $period_year); // first day of year
201
            $doc_date_end = dol_mktime(23, 59, 59, 12, 31, $period_year); // last day of year
202
        } elseif ($period == 'fiscalyear' || $period == 'lastfiscalyear' || $period == 'actualandlastfiscalyear') {
203
            // find actual fiscal year
204
            $cur_fiscal_period = getCurrentPeriodOfFiscalYear($this->db, $conf);
205
            $cur_fiscal_date_start = $cur_fiscal_period['date_start'];
206
            $cur_fiscal_date_end = $cur_fiscal_period['date_end'];
207
208
            if ($period == 'fiscalyear') {
209
                $doc_date_start = $cur_fiscal_date_start;
210
                $doc_date_end = $cur_fiscal_date_end;
211
            } else {
212
                // get one day before current fiscal date start (to find previous fiscal period)
213
                $prev_fiscal_date_search = dol_time_plus_duree($cur_fiscal_date_start, -1, 'd');
214
215
                // find previous fiscal year from current fiscal year
216
                $prev_fiscal_period = getCurrentPeriodOfFiscalYear($this->db, $conf, $prev_fiscal_date_search);
217
                $prev_fiscal_date_start = $prev_fiscal_period['date_start'];
218
                $prev_fiscal_date_end = $prev_fiscal_period['date_end'];
219
220
                if ($period == 'lastfiscalyear') {
221
                    $doc_date_start = $prev_fiscal_date_start;
222
                    $doc_date_end = $prev_fiscal_date_end;
223
                } else {
224
                    // period == 'actualandlastfiscalyear'
225
                    $doc_date_start = $prev_fiscal_date_start;
226
                    $doc_date_end = $cur_fiscal_date_end;
227
                }
228
            }
229
        }
230
        if (is_numeric($doc_date_start)) {
231
            $filter['t.doc_date>='] = $doc_date_start;
232
        }
233
        if (is_numeric($doc_date_end)) {
234
            $filter['t.doc_date<='] = $doc_date_end;
235
        }
236
237
        // @FIXME Critical bugged. Never use fetchAll without limit !
238
        $result = $bookkeeping->fetchAll($sortorder, $sortfield, 0, 0, $filter, 'AND', $alreadyexport);
239
240
        if ($result < 0) {
241
            throw new RestException(500, 'Error bookkeeping fetch all : ' . $bookkeeping->errorsToString());
242
        } else {
243
            // export files then exit
244
            if (empty($lettering)) {
245
                if (is_array($bookkeeping->lines)) {
246
                    foreach ($bookkeeping->lines as $k => $movement) {
247
                        unset($bookkeeping->lines[$k]->lettering_code);
248
                        unset($bookkeeping->lines[$k]->date_lettering);
249
                    }
250
                }
251
            }
252
253
            $error = 0;
254
            $this->db->begin();
255
256
            if (empty($notnotifiedasexport)) {
257
                if (is_array($bookkeeping->lines)) {
258
                    foreach ($bookkeeping->lines as $movement) {
259
                        $now = dol_now();
260
261
                        $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
262
                        $sql .= " SET date_export = '" . $this->db->idate($now) . "'";
263
                        $sql .= " WHERE rowid = " . ((int) $movement->id);
264
265
                        $result = $this->db->query($sql);
266
                        if (!$result) {
267
                            $accountancyexport->errors[] = $langs->trans('NotAllExportedMovementsCouldBeRecordedAsExportedOrValidated');
268
                            $error++;
269
                            break;
270
                        }
271
                    }
272
                }
273
            }
274
275
            // export and only write file without downloading
276
            if (!$error) {
277
                $result = $accountancyexport->export($bookkeeping->lines, $format_number, 0, 1, 2);
278
                if ($result < 0) {
279
                    $error++;
280
                }
281
            }
282
283
            if ($error) {
284
                $this->db->rollback();
285
                throw new RestException(500, 'Error accountancy export : ' . implode(',', $accountancyexport->errors));
286
            } else {
287
                $this->db->commit();
288
                exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
289
            }
290
        }
291
    }
292
}
293