Passed
Branch develop (01f96b)
by
unknown
30:45
created

BankAccounts   F

Complexity

Total Complexity 70

Size/Duplication

Total Lines 522
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 209
c 1
b 0
f 0
dl 0
loc 522
rs 2.8
wmc 70

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
F transfer() 0 112 19
A _cleanObjectDatas() 0 8 1
C index() 0 57 12
A put() 0 24 6
A delete() 0 19 4
B getLines() 0 46 8
A _validate() 0 9 3
A get() 0 13 3
A addLink() 0 23 5
A post() 0 22 4
A addLine() 0 26 4

How to fix   Complexity   

Complex Class

Complex classes like BankAccounts 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 BankAccounts, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * Copyright (C) 2016 Xebax Christy <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
use Luracast\Restler\RestException;
20
21
require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
22
23
/**
24
 * API class for accounts
25
 *
26
 * @property DoliDB db
27
 * @access protected
28
 * @class DolibarrApiAccess {@requires user,external}
29
 */
30
class BankAccounts extends DolibarrApi
31
{
32
33
    /**
34
     * array $FIELDS Mandatory fields, checked when creating an object
35
     */
36
    static $FIELDS = array(
37
        'ref',
38
        'label',
39
        'type',
40
        'currency_code',
41
        'country_id'
42
    );
43
44
    /**
45
     * Constructor
46
     */
47
    public function __construct()
48
    {
49
        global $db;
50
        $this->db = $db;
51
    }
52
53
    /**
54
     * Get the list of accounts.
55
     *
56
     * @param string    $sortfield  Sort field
57
     * @param string    $sortorder  Sort order
58
     * @param int       $limit      Limit for list
59
     * @param int       $page       Page number
60
	 * @param  int    	$category   Use this param to filter list by category
61
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.import_key:<:'20160101')"
62
     * @return array                List of account objects
63
     *
64
     * @throws RestException
65
     */
66
    public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $category = 0, $sqlfilters = '')
67
    {
68
        $list = array();
69
70
        if (!DolibarrApiAccess::$user->rights->banque->lire) {
71
            throw new RestException(401);
72
        }
73
74
        $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."bank_account as t";
75
    	if ($category > 0) {
76
        $sql .= ", ".MAIN_DB_PREFIX."categorie_account as c";
77
		}
78
        $sql .= ' WHERE t.entity IN ('.getEntity('bank_account').')';
79
    	// Select accounts of given category
80
    	if ($category > 0) {
81
        $sql .= " AND c.fk_categorie = ".$db->escape($category)." AND c.fk_account = t.rowid ";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $db seems to be never defined.
Loading history...
82
		}
83
        // Add sql filters
84
        if ($sqlfilters)
85
        {
86
            if (!DolibarrApi::_checkFilters($sqlfilters))
87
            {
88
                throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
89
            }
90
            $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
91
            $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
92
        }
93
94
        $sql .= $this->db->order($sortfield, $sortorder);
95
        if ($limit) {
96
            if ($page < 0)
97
            {
98
                $page = 0;
99
            }
100
            $offset = $limit * $page;
101
102
            $sql .= $this->db->plimit($limit + 1, $offset);
103
        }
104
105
        dol_syslog("API Rest request");
106
        $result = $this->db->query($sql);
107
108
        if ($result) {
109
            $num = $this->db->num_rows($result);
110
            $min = min($num, ($limit <= 0 ? $num : $limit));
111
            for ($i = 0; $i < $min; $i++) {
112
                $obj = $this->db->fetch_object($result);
113
                $account = new Account($this->db);
114
                if ($account->fetch($obj->rowid) > 0) {
115
                    $list[] = $this->_cleanObjectDatas($account);
116
                }
117
            }
118
        } else {
119
            throw new RestException(503, 'Error when retrieving list of accounts: '.$this->db->lasterror());
120
        }
121
122
        return $list;
123
    }
124
125
    /**
126
     * Get account by ID.
127
     *
128
     * @param int    $id    ID of account
129
     * @return array Account object
130
     *
131
     * @throws RestException
132
     */
133
    public function get($id)
134
    {
135
        if (!DolibarrApiAccess::$user->rights->banque->lire) {
136
            throw new RestException(401);
137
        }
138
139
        $account = new Account($this->db);
140
        $result = $account->fetch($id);
141
        if (!$result) {
142
            throw new RestException(404, 'account not found');
143
        }
144
145
        return $this->_cleanObjectDatas($account);
146
    }
147
148
    /**
149
     * Create account object
150
     *
151
     * @param array $request_data    Request data
152
     * @return int ID of account
153
     */
154
    public function post($request_data = null)
155
    {
156
        if (!DolibarrApiAccess::$user->rights->banque->configurer) {
157
            throw new RestException(401);
158
        }
159
        // Check mandatory fields
160
        $result = $this->_validate($request_data);
161
162
        $account = new Account($this->db);
163
        foreach ($request_data as $field => $value) {
164
            $account->$field = $value;
165
        }
166
        // Date of the initial balance (required to create an account).
167
        $account->date_solde = time();
168
        // courant and type are the same thing but the one used when
169
        // creating an account is courant
170
        $account->courant = $account->type;
171
172
        if ($account->create(DolibarrApiAccess::$user) < 0) {
173
            throw new RestException(500, 'Error creating bank account', array_merge(array($account->error), $account->errors));
174
        }
175
        return $account->id;
176
    }
177
178
    /**
179
     * Create an internal wire transfer between two bank accounts
180
     *
181
     * @param int     $bankaccount_from_id  BankAccount ID to use as the source of the internal wire transfer		{@from body}{@required true}
182
     * @param int     $bankaccount_to_id    BankAccount ID to use as the destination of the internal wire transfer  {@from body}{@required true}
183
     * @param string  $date					Date of the internal wire transfer (UNIX timestamp)						{@from body}{@required true}{@type timestamp}
184
     * @param string  $description			Description of the internal wire transfer								{@from body}{@required true}
185
     * @param float	  $amount				Amount to transfer from the source to the destination BankAccount		{@from body}{@required true}
186
     * @param float	  $amount_to			Amount to transfer to the destination BankAccount (only when accounts does not share the same currency)		{@from body}{@required false}
187
     *
188
     * @url POST    /transfer
189
     *
190
     * @return array
191
     *
192
     * @status 201
193
     *
194
     * @throws RestException 401 Unauthorized: User does not have permission to configure bank accounts
195
	 * @throws RestException 404 Not Found: Either the source or the destination bankaccount for the provided id does not exist
196
     * @throws RestException 422 Unprocessable Entity: Refer to detailed exception message for the cause
197
	 * @throws RestException 500 Internal Server Error: Error(s) returned by the RDBMS
198
     */
199
    public function transfer($bankaccount_from_id = 0, $bankaccount_to_id = 0, $date = null, $description = "", $amount = 0.0, $amount_to = 0.0)
200
    {
201
        if (!DolibarrApiAccess::$user->rights->banque->configurer) {
202
            throw new RestException(401);
203
        }
204
205
        if ($bankaccount_from_id === $bankaccount_to_id) {
206
            throw new RestException(422, 'bankaccount_from_id and bankaccount_to_id must be different !');
207
        }
208
209
        require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
210
211
        $accountfrom = new Account($this->db);
212
        $resultAccountFrom = $accountfrom->fetch($bankaccount_from_id);
213
214
        if ($resultAccountFrom === 0) {
215
            throw new RestException(404, 'The BankAccount for bankaccount_from_id provided does not exist.');
216
        }
217
218
        $accountto = new Account($this->db);
219
        $resultAccountTo = $accountto->fetch($bankaccount_to_id);
220
221
        if ($resultAccountTo === 0) {
222
            throw new RestException(404, 'The BankAccount for bankaccount_to_id provided does not exist.');
223
        }
224
225
        if ($accountto->currency_code == $accountfrom->currency_code)
226
        {
227
            $amount_to = $amount;
228
        }
229
        else
230
        {
231
            if (!$amount_to || empty($amount_to))
232
            {
233
                throw new RestException(422, 'You must provide amount_to value since bankaccount_from and bankaccount_to does not share the same currency.');
234
            }
235
        }
236
237
        $this->db->begin();
238
239
        $error = 0;
240
        $bank_line_id_from = 0;
241
        $bank_line_id_to = 0;
242
        $result = 0;
243
        $user = DolibarrApiAccess::$user;
244
245
        // By default, electronic transfert from bank to bank
246
        $typefrom = 'PRE';
247
        $typeto = 'VIR';
248
249
        if ($accountto->courant == Account::TYPE_CASH || $accountfrom->courant == Account::TYPE_CASH)
250
        {
251
            // This is transfer of change
252
            $typefrom = 'LIQ';
253
            $typeto = 'LIQ';
254
        }
255
256
        /**
257
         * Creating bank line records
258
         */
259
260
        if (!$error) {
261
            $bank_line_id_from = $accountfrom->addline($date, $typefrom, $description, -1 * price2num($amount), '', '', $user);
262
        }
263
        if (!($bank_line_id_from > 0)) {
264
            $error++;
265
        }
266
267
        if (!$error) {
268
            $bank_line_id_to = $accountto->addline($date, $typeto, $description, price2num($amount_to), '', '', $user);
269
        }
270
        if (!($bank_line_id_to > 0)) {
271
            $error++;
272
        }
273
274
        /**
275
         * Creating links between bank line record and its source
276
         */
277
278
        $url = DOL_URL_ROOT.'/compta/bank/line.php?rowid=';
279
        $label = '(banktransfert)';
280
        $type = 'banktransfert';
281
282
        if (!$error) {
283
            $result = $accountfrom->add_url_line($bank_line_id_from, $bank_line_id_to, $url, $label, $type);
284
        }
285
        if (!($result > 0)) {
286
            $error++;
287
        }
288
289
        if (!$error) {
290
            $result = $accountto->add_url_line($bank_line_id_to, $bank_line_id_from, $url, $label, $type);
291
        }
292
        if (!($result > 0)) {
293
            $error++;
294
        }
295
296
        if (!$error)
297
        {
298
            $this->db->commit();
299
300
            return array(
301
                'success' => array(
302
                    'code' => 201,
303
                    'message' => 'Internal wire transfer created successfully.'
304
                )
305
            );
306
        }
307
        else
308
        {
309
            $this->db->rollback();
310
            throw new RestException(500, $accountfrom->error.' '.$accountto->error);
311
        }
312
    }
313
314
    /**
315
     * Update account
316
     *
317
     * @param int    $id              ID of account
318
     * @param array  $request_data    data
319
     * @return int
320
     */
321
    public function put($id, $request_data = null)
322
    {
323
        if (!DolibarrApiAccess::$user->rights->banque->configurer) {
324
            throw new RestException(401);
325
        }
326
327
        $account = new Account($this->db);
328
        $result = $account->fetch($id);
329
        if (!$result) {
330
            throw new RestException(404, 'account not found');
331
        }
332
333
        foreach ($request_data as $field => $value) {
334
            if ($field == 'id') continue;
335
            $account->$field = $value;
336
        }
337
338
        if ($account->update(DolibarrApiAccess::$user) > 0)
339
        {
340
            return $this->get($id);
341
        }
342
        else
343
        {
344
            throw new RestException(500, $account->error);
345
        }
346
    }
347
348
    /**
349
     * Delete account
350
     *
351
     * @param int    $id    ID of account
352
     * @return array
353
     */
354
    public function delete($id)
355
    {
356
        if (!DolibarrApiAccess::$user->rights->banque->configurer) {
357
            throw new RestException(401);
358
        }
359
        $account = new Account($this->db);
360
        $result = $account->fetch($id);
361
        if (!$result) {
362
            throw new RestException(404, 'account not found');
363
        }
364
365
        if ($account->delete(DolibarrApiAccess::$user) < 0) {
366
            throw new RestException(401, 'error when deleting account');
367
        }
368
369
        return array(
370
            'success' => array(
371
                'code' => 200,
372
                'message' => 'account deleted'
373
            )
374
        );
375
    }
376
377
    /**
378
     * Validate fields before creating an object
379
     *
380
     * @param array|null    $data    Data to validate
381
     * @return array
382
     *
383
     * @throws RestException
384
     */
385
    private function _validate($data)
386
    {
387
        $account = array();
388
        foreach (BankAccounts::$FIELDS as $field) {
389
            if (!isset($data[$field]))
390
                throw new RestException(400, "$field field missing");
391
            $account[$field] = $data[$field];
392
        }
393
        return $account;
394
    }
395
396
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
397
    /**
398
     * Clean sensible object datas
399
     *
400
     * @param object    $object    Object to clean
401
     * @return array Array of cleaned object properties
402
     */
403
    protected function _cleanObjectDatas($object)
404
    {
405
        // phpcs:enable
406
        $object = parent::_cleanObjectDatas($object);
407
408
        unset($object->rowid);
409
410
        return $object;
411
    }
412
413
    /**
414
     * Get the list of lines of the account.
415
     *
416
     * @param int $id ID of account
417
     * @return array Array of AccountLine objects
418
     *
419
     * @throws RestException
420
     *
421
     * @url GET {id}/lines
422
	 * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.import_key:<:'20160101')"
423
     */
424
    public function getLines($id, $sqlfilters = '')
425
    {
426
        $list = array();
427
428
        if (!DolibarrApiAccess::$user->rights->banque->lire) {
429
            throw new RestException(401);
430
        }
431
432
        $account = new Account($this->db);
433
        $result = $account->fetch($id);
434
        if (!$result) {
435
            throw new RestException(404, 'account not found');
436
        }
437
438
        $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."bank ";
439
        $sql .= " WHERE fk_account = ".$id;
440
441
		// Add sql filters
442
		if ($sqlfilters)
443
		{
444
			if (!DolibarrApi::_checkFilters($sqlfilters))
445
			{
446
				throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
447
			}
448
			$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
449
			$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
450
		}
451
452
        $sql .= " ORDER BY rowid";
453
454
        $result = $this->db->query($sql);
455
456
        if ($result) {
457
            $num = $this->db->num_rows($result);
458
            for ($i = 0; $i < $num; $i++) {
459
                $obj = $this->db->fetch_object($result);
460
                $accountLine = new AccountLine($this->db);
461
                if ($accountLine->fetch($obj->rowid) > 0) {
462
                    $list[] = $this->_cleanObjectDatas($accountLine);
463
                }
464
            }
465
        } else {
466
            throw new RestException(503, 'Error when retrieving list of account lines: '.$accountLine->error);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $accountLine seems to be never defined.
Loading history...
467
        }
468
469
        return $list;
470
    }
471
472
    /**
473
     * Add a line to an account
474
     *
475
     * @param int    $id            ID of account
476
     * @param int    $date          Payment date (timestamp) {@from body} {@type timestamp}
477
     * @param string $type          Payment mode (TYP,VIR,PRE,LIQ,VAD,CB,CHQ...) {@from body}
478
     * @param string $label         Label {@from body}
479
     * @param float  $amount        Amount (may be 0) {@from body}
480
     * @param int    $category      Category
481
     * @param string $cheque_number Cheque numberl {@from body}
482
     * @param string $cheque_writer Name of cheque writer {@from body}
483
     * @param string $cheque_bank   Bank of cheque writer {@from body}
484
     * @return int  ID of line
485
     *
486
     * @url POST {id}/lines
487
     */
488
    public function addLine($id, $date, $type, $label, $amount, $category = 0, $cheque_number = '', $cheque_writer = '', $cheque_bank = '')
489
    {
490
        if (!DolibarrApiAccess::$user->rights->banque->modifier) {
491
            throw new RestException(401);
492
        }
493
494
        $account = new Account($this->db);
495
        $result = $account->fetch($id);
496
        if (!$result) {
497
            throw new RestException(404, 'account not found');
498
        }
499
500
        $result = $account->addline(
501
            $date,
502
            $type,
503
            $label,
504
            $amount,
505
            $cheque_number,
506
            $category,
507
            DolibarrApiAccess::$user,
508
            $cheque_writer, $cheque_bank
509
        );
510
        if ($result < 0) {
511
            throw new RestException(503, 'Error when adding line to account: '.$account->error);
512
        }
513
        return $result;
514
    }
515
516
    /**
517
     * Add a link to an account line
518
     *
519
     * @param int    $id    		ID of account
520
     * @param int    $line_id       ID of account line
521
     * @param int    $url_id        ID to set in the URL {@from body}
522
     * @param string $url           URL of the link {@from body}
523
     * @param string $label         Label {@from body}
524
     * @param string $type          Type of link ('payment', 'company', 'member', ...) {@from body}
525
     * @return int  ID of link
526
     *
527
     * @url POST {id}/lines/{line_id}/links
528
     */
529
    public function addLink($id, $line_id, $url_id, $url, $label, $type)
530
    {
531
        if (!DolibarrApiAccess::$user->rights->banque->modifier) {
532
            throw new RestException(401);
533
        }
534
535
        $account = new Account($this->db);
536
        $result = $account->fetch($id);
537
        if (!$result) {
538
            throw new RestException(404, 'account not found');
539
        }
540
541
        $accountLine = new AccountLine($this->db);
542
        $result = $accountLine->fetch($line_id);
543
        if (!$result) {
544
            throw new RestException(404, 'account line not found');
545
        }
546
547
        $result = $account->add_url_line($line_id, $url_id, $url, $label, $type);
548
        if ($result < 0) {
549
            throw new RestException(503, 'Error when adding link to account line: '.$account->error);
550
        }
551
        return $result;
552
    }
553
}
554