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

Accountancy   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 242
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 129
dl 0
loc 242
rs 8.96
c 0
b 0
f 0
wmc 43

2 Methods

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

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