Passed
Push — CHECK_API ( 78ffdd...fa4f39 )
by Rafael
41:29
created

Invoices   F

Complexity

Total Complexity 277

Size/Duplication

Total Lines 1817
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 753
dl 0
loc 1817
rs 1.847
c 0
b 0
f 0
wmc 277

35 Methods

Rating   Name   Duplication   Size   Complexity  
A _fetch() 0 36 6
A get() 0 3 1
B post() 0 33 7
F index() 0 97 23
A getByRefExt() 0 3 1
A getByRef() 0 3 1
A __construct() 0 6 1
A getDiscount() 0 28 6
B settopaid() 0 33 8
B addContact() 0 29 7
A deleteLine() 0 23 6
C put() 0 51 14
A getTemplateInvoice() 0 3 1
A getLines() 0 20 5
A createInvoiceFromContract() 0 25 6
B useDiscount() 0 27 7
A _cleanObjectDatas() 0 14 1
B settodraft() 0 32 8
A putPayment() 0 28 6
C addPayment() 0 91 16
A getPayments() 0 24 6
B deleteContact() 0 29 8
A postContact() 0 30 6
A delete() 0 25 6
A _validate() 0 10 3
F addPaymentDistributed() 0 117 31
B settounpaid() 0 33 8
B useCreditNote() 0 29 7
A _cleanTemplateObjectDatas() 0 14 1
B putLine() 0 55 6
A createInvoiceFromOrder() 0 24 6
F markAsCreditAvailable() 0 154 34
A _fetchTemplateInvoice() 0 25 6
B validate() 0 36 8
B postLine() 0 67 10

How to fix   Complexity   

Complex Class

Complex classes like Invoices 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 Invoices, 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) 2020   Thibault FOUCART		<[email protected]>
5
 * Copyright (C) 2023	Joachim Kueter			<[email protected]>
6
 * Copyright (C) 2024		Frédéric France			<[email protected]>
7
 * Copyright (C) 2024		MDW							<[email protected]>
8
 * Copyright (C) 2024       Rafael San José             <[email protected]>
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23
24
use Dolibarr\Code\Adherents\Classes\Adherent;
25
use Luracast\Restler\RestException;
26
27
require_once constant('DOL_DOCUMENT_ROOT') . '/compta/facture/class/facture-rec.class.php';
28
29
30
/**
31
 * API class for invoices
32
 *
33
 * @access protected
34
 * @class  DolibarrApiAccess {@requires user,external}
35
 */
36
class Invoices extends DolibarrApi
37
{
38
    /**
39
     *
40
     * @var array   $FIELDS     Mandatory fields, checked when create and update object
41
     */
42
    public static $FIELDS = array(
43
        'socid',
44
    );
45
46
    /**
47
     * @var Facture $invoice {@type Facture}
48
     */
49
    private $invoice;
50
51
    /**
52
     * @var FactureRec $templte_invoice {@type FactureRec}
53
     */
54
    private $template_invoice;
55
56
57
    /**
58
     * Constructor
59
     */
60
    public function __construct()
61
    {
62
        global $db;
63
        $this->db = $db;
64
        $this->invoice = new Facture($this->db);
65
        $this->template_invoice = new FactureRec($this->db);
66
    }
67
68
    /**
69
     * Get properties of a invoice object
70
     *
71
     * Return an array with invoice information
72
     *
73
     * @param   int     $id             ID of invoice
74
     * @param   int     $contact_list   0:Return array contains all properties, 1:Return array contains just id, -1: Do not return contacts/adddesses
75
     * @return  Object                  Object with cleaned properties
76
     *
77
     * @throws  RestException
78
     */
79
    public function get($id, $contact_list = 1)
80
    {
81
        return $this->_fetch($id, '', '', $contact_list);
82
    }
83
84
    /**
85
     * Get properties of an invoice object by ref
86
     *
87
     * Return an array with invoice information
88
     *
89
     * @param   string      $ref            Ref of object
90
     * @param   int         $contact_list   0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id, -1: Do not return contacts/adddesses
91
     * @return  Object                      Object with cleaned properties
92
     *
93
     * @url GET    ref/{ref}
94
     *
95
     * @throws  RestException
96
     */
97
    public function getByRef($ref, $contact_list = 1)
98
    {
99
        return $this->_fetch('', $ref, '', $contact_list);
100
    }
101
102
    /**
103
     * Get properties of an invoice object by ref_ext
104
     *
105
     * Return an array with invoice information
106
     *
107
     * @param   string      $ref_ext        External reference of object
108
     * @param   int         $contact_list   0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id, -1: Do not return contacts/adddesses
109
     * @return  Object                      Object with cleaned properties
110
     *
111
     * @url GET    ref_ext/{ref_ext}
112
     *
113
     * @throws  RestException
114
     */
115
    public function getByRefExt($ref_ext, $contact_list = 1)
116
    {
117
        return $this->_fetch('', '', $ref_ext, $contact_list);
118
    }
119
120
    /**
121
     * Get properties of an invoice object
122
     *
123
     * Return an array with invoice information
124
     *
125
     * @param   int         $id             ID of order
126
     * @param   string      $ref            Ref of object
127
     * @param   string      $ref_ext        External reference of object
128
     * @param   int         $contact_list   0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id, -1: Do not return contacts/adddesses
129
     * @return  Object                      Object with cleaned properties
130
     *
131
     * @throws  RestException
132
     */
133
    private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = 1)
134
    {
135
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
136
            throw new RestException(403);
137
        }
138
139
        $result = $this->invoice->fetch($id, $ref, $ref_ext);
140
        if (!$result) {
141
            throw new RestException(404, 'Invoice not found');
142
        }
143
144
        // Get payment details
145
        $this->invoice->totalpaid = $this->invoice->getSommePaiement();
146
        $this->invoice->totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
147
        $this->invoice->totaldeposits = $this->invoice->getSumDepositsUsed();
148
        $this->invoice->remaintopay = price2num($this->invoice->total_ttc - $this->invoice->totalpaid - $this->invoice->totalcreditnotes - $this->invoice->totaldeposits, 'MT');
149
150
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
151
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
152
        }
153
154
        // Add external contacts ids
155
        if ($contact_list > -1) {
156
            $tmparray = $this->invoice->liste_contact(-1, 'external', $contact_list);
157
            if (is_array($tmparray)) {
158
                $this->invoice->contacts_ids = $tmparray;
159
            }
160
        }
161
162
        $this->invoice->fetchObjectLinked();
163
164
        // Add online_payment_url, copied from order
165
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
166
        $this->invoice->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $this->invoice->ref);
167
168
        return $this->_cleanObjectDatas($this->invoice);
169
    }
170
171
    /**
172
     * List invoices
173
     *
174
     * Get a list of invoices
175
     *
176
     * @param string    $sortfield        Sort field
177
     * @param string    $sortorder        Sort order
178
     * @param int       $limit            Limit for list
179
     * @param int       $page             Page number
180
     * @param string    $thirdparty_ids   Thirdparty ids to filter orders of (example '1' or '1,2,3') {@pattern /^[0-9,]*$/i}
181
     * @param string    $status           Filter by invoice status : draft | unpaid | paid | cancelled
182
     * @param string    $sqlfilters       Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
183
     * @param string    $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names
184
     * @return array                      Array of invoice objects
185
     *
186
     * @throws RestException 404 Not found
187
     * @throws RestException 503 Error
188
     */
189
    public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $status = '', $sqlfilters = '', $properties = '')
190
    {
191
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
192
            throw new RestException(403);
193
        }
194
195
        $obj_ret = array();
196
197
        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
198
        $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
199
200
        // If the internal user must only see his customers, force searching by him
201
        $search_sale = 0;
202
        if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
203
            $search_sale = DolibarrApiAccess::$user->id;
204
        }
205
206
        $sql = "SELECT t.rowid";
207
        $sql .= " FROM " . MAIN_DB_PREFIX . "facture AS t";
208
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "facture_extrafields AS ef ON (ef.fk_object = t.rowid)"; // Modification VMR Global Solutions to include extrafields as search parameters in the API GET call, so we will be able to filter on extrafields
209
        $sql .= ' WHERE t.entity IN (' . getEntity('invoice') . ')';
210
        if ($socids) {
211
            $sql .= " AND t.fk_soc IN (" . $this->db->sanitize($socids) . ")";
212
        }
213
        // Search on sale representative
214
        if ($search_sale && $search_sale != '-1') {
215
            if ($search_sale == -2) {
216
                $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
217
            } elseif ($search_sale > 0) {
218
                $sql .= " AND EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc AND sc.fk_user = " . ((int) $search_sale) . ")";
219
            }
220
        }
221
        // Filter by status
222
        if ($status == 'draft') {
223
            $sql .= " AND t.fk_statut IN (0)";
224
        }
225
        if ($status == 'unpaid') {
226
            $sql .= " AND t.fk_statut IN (1)";
227
        }
228
        if ($status == 'paid') {
229
            $sql .= " AND t.fk_statut IN (2)";
230
        }
231
        if ($status == 'cancelled') {
232
            $sql .= " AND t.fk_statut IN (3)";
233
        }
234
        // Add sql filters
235
        if ($sqlfilters) {
236
            $errormessage = '';
237
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
238
            if ($errormessage) {
239
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
240
            }
241
        }
242
243
        $sql .= $this->db->order($sortfield, $sortorder);
244
        if ($limit) {
245
            if ($page < 0) {
246
                $page = 0;
247
            }
248
            $offset = $limit * $page;
249
250
            $sql .= $this->db->plimit($limit + 1, $offset);
251
        }
252
253
        $result = $this->db->query($sql);
254
        if ($result) {
255
            $i = 0;
256
            $num = $this->db->num_rows($result);
257
            $min = min($num, ($limit <= 0 ? $num : $limit));
258
            while ($i < $min) {
259
                $obj = $this->db->fetch_object($result);
260
                $invoice_static = new Facture($this->db);
261
                if ($invoice_static->fetch($obj->rowid)) {
262
                    // Get payment details
263
                    $invoice_static->totalpaid = $invoice_static->getSommePaiement();
264
                    $invoice_static->totalcreditnotes = $invoice_static->getSumCreditNotesUsed();
265
                    $invoice_static->totaldeposits = $invoice_static->getSumDepositsUsed();
266
                    $invoice_static->remaintopay = price2num($invoice_static->total_ttc - $invoice_static->totalpaid - $invoice_static->totalcreditnotes - $invoice_static->totaldeposits, 'MT');
267
268
                    // Add external contacts ids
269
                    $tmparray = $invoice_static->liste_contact(-1, 'external', 1);
270
                    if (is_array($tmparray)) {
271
                        $invoice_static->contacts_ids = $tmparray;
272
                    }
273
                    // Add online_payment_url, copied from order
274
                    require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
275
                    $invoice_static->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $invoice_static->ref);
276
277
                    $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($invoice_static), $properties);
278
                }
279
                $i++;
280
            }
281
        } else {
282
            throw new RestException(503, 'Error when retrieve invoice list : ' . $this->db->lasterror());
283
        }
284
285
        return $obj_ret;
286
    }
287
288
    /**
289
     * Create invoice object
290
     *
291
     * @param array $request_data   Request datas
292
     * @return int                  ID of invoice
293
     */
294
    public function post($request_data = null)
295
    {
296
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
297
            throw new RestException(403, "Insuffisant rights");
298
        }
299
        // Check mandatory fields
300
        $result = $this->_validate($request_data);
301
302
        foreach ($request_data as $field => $value) {
303
            if ($field === 'caller') {
304
                // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
305
                $this->invoice->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
306
                continue;
307
            }
308
309
            $this->invoice->$field = $this->_checkValForAPI($field, $value, $this->invoice);
310
        }
311
        if (!array_key_exists('date', $request_data)) {
312
            $this->invoice->date = dol_now();
313
        }
314
        /* We keep lines as an array
315
         if (isset($request_data["lines"])) {
316
            $lines = array();
317
            foreach ($request_data["lines"] as $line) {
318
                array_push($lines, (object) $line);
319
            }
320
            $this->invoice->lines = $lines;
321
        }*/
322
323
        if ($this->invoice->create(DolibarrApiAccess::$user, 0, (empty($request_data["date_lim_reglement"]) ? 0 : $request_data["date_lim_reglement"])) < 0) {
324
            throw new RestException(500, "Error creating invoice", array_merge(array($this->invoice->error), $this->invoice->errors));
325
        }
326
        return ((int) $this->invoice->id);
327
    }
328
329
    /**
330
     * Create an invoice using an existing order.
331
     *
332
     * @param int   $orderid       Id of the order
333
     * @return  Object              Object with cleaned properties
334
     *
335
     * @url     POST /createfromorder/{orderid}
336
     *
337
     * @throws RestException 400
338
     * @throws RestException 401
339
     * @throws RestException 404
340
     * @throws RestException 405
341
     */
342
    public function createInvoiceFromOrder($orderid)
343
    {
344
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
345
            throw new RestException(403);
346
        }
347
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
348
            throw new RestException(403);
349
        }
350
        if (empty($orderid)) {
351
            throw new RestException(400, 'Order ID is mandatory');
352
        }
353
354
        $order = new Commande($this->db);
355
        $result = $order->fetch($orderid);
356
        if (!$result) {
357
            throw new RestException(404, 'Order not found');
358
        }
359
360
        $result = $this->invoice->createFromOrder($order, DolibarrApiAccess::$user);
361
        if ($result < 0) {
362
            throw new RestException(405, $this->invoice->error);
363
        }
364
        $this->invoice->fetchObjectLinked();
365
        return $this->_cleanObjectDatas($this->invoice);
366
    }
367
368
    /**
369
    * Create an invoice using a contract.
370
    *
371
    * @param int   $contractid       Id of the contract
372
    * @return     Object                          Object with cleaned properties
373
    *
374
    * @url     POST /createfromcontract/{contractid}
375
    *
376
    * @throws RestException 400
377
    * @throws RestException 401
378
    * @throws RestException 404
379
    * @throws RestException 405
380
    */
381
    public function createInvoiceFromContract($contractid)
382
    {
383
    
384
        if (!DolibarrApiAccess::$user->hasRight('contrat', 'lire')) {
385
            throw new RestException(403);
386
        }
387
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
388
            throw new RestException(403);
389
        }
390
        if (empty($contractid)) {
391
            throw new RestException(400, 'Contract ID is mandatory');
392
        }
393
394
        $contract = new Contrat($this->db);
395
        $result = $contract->fetch($contractid);
396
        if (!$result) {
397
            throw new RestException(404, 'Contract not found');
398
        }
399
400
        $result = $this->invoice->createFromContract($contract, DolibarrApiAccess::$user);
401
        if ($result < 0) {
402
            throw new RestException(405, $this->invoice->error);
403
        }
404
        $this->invoice->fetchObjectLinked();
405
        return $this->_cleanObjectDatas($this->invoice);
406
    }
407
408
    /**
409
     * Get lines of an invoice
410
     *
411
     * @param   int   $id               Id of invoice
412
     * @return  array                   Array of lines
413
     *
414
     * @url GET {id}/lines
415
     */
416
    public function getLines($id)
417
    {
418
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
419
            throw new RestException(403);
420
        }
421
422
        $result = $this->invoice->fetch($id);
423
        if (!$result) {
424
            throw new RestException(404, 'Invoice not found');
425
        }
426
427
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
428
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
429
        }
430
        $this->invoice->getLinesArray();
431
        $result = array();
432
        foreach ($this->invoice->lines as $line) {
433
            array_push($result, $this->_cleanObjectDatas($line));
434
        }
435
        return $result;
436
    }
437
438
    /**
439
     * Update a line to a given invoice
440
     *
441
     * @param   int   $id             Id of invoice to update
442
     * @param   int   $lineid         Id of line to update
443
     * @param   array $request_data   InvoiceLine data
444
     * @return  Object                Object with cleaned properties
445
     *
446
     * @url PUT {id}/lines/{lineid}
447
     *
448
     * @throws RestException 304
449
     * @throws RestException 401
450
     * @throws RestException 404 Invoice not found
451
     */
452
    public function putLine($id, $lineid, $request_data = null)
453
    {
454
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
455
            throw new RestException(403);
456
        }
457
458
        $result = $this->invoice->fetch($id);
459
        if (!$result) {
460
            throw new RestException(404, 'Invoice not found');
461
        }
462
463
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
464
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
465
        }
466
467
        $request_data = (object) $request_data;
468
469
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
470
        $request_data->label = sanitizeVal($request_data->label);
471
472
        $updateRes = $this->invoice->updateline(
473
            $lineid,
474
            $request_data->desc,
475
            $request_data->subprice,
476
            $request_data->qty,
477
            $request_data->remise_percent,
478
            $request_data->date_start,
479
            $request_data->date_end,
480
            $request_data->tva_tx,
481
            $request_data->localtax1_tx,
482
            $request_data->localtax2_tx,
483
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
484
            $request_data->info_bits,
485
            $request_data->product_type,
486
            $request_data->fk_parent_line,
487
            0,
488
            $request_data->fk_fournprice,
489
            $request_data->pa_ht,
490
            $request_data->label,
491
            $request_data->special_code,
492
            $request_data->array_options,
493
            $request_data->situation_percent,
494
            $request_data->fk_unit,
495
            $request_data->multicurrency_subprice,
496
            0,
497
            $request_data->ref_ext,
498
            $request_data->rang
499
        );
500
501
        if ($updateRes > 0) {
502
            $result = $this->get($id);
503
            unset($result->line);
504
            return $this->_cleanObjectDatas($result);
505
        } else {
506
            throw new RestException(304, $this->invoice->error);
507
        }
508
    }
509
510
    /**
511
     * Add a contact type of given invoice
512
     *
513
     * @param   int    $id             Id of invoice to update
514
     * @param   int    $contactid      Id of contact to add
515
     * @param   string $type           Type of the contact (BILLING, SHIPPING, CUSTOMER)
516
     * @return  array
517
     *
518
     * @url POST {id}/contact/{contactid}/{type}
519
     *
520
     * @throws RestException 401
521
     * @throws RestException 404
522
     */
523
    public function postContact($id, $contactid, $type)
524
    {
525
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
526
            throw new RestException(403);
527
        }
528
529
        $result = $this->invoice->fetch($id);
530
531
        if (!$result) {
532
            throw new RestException(404, 'Invoice not found');
533
        }
534
535
        if (!in_array($type, array('BILLING', 'SHIPPING', 'CUSTOMER'), true)) {
536
            throw new RestException(500, 'Availables types: BILLING, SHIPPING OR CUSTOMER');
537
        }
538
539
        if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
540
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
541
        }
542
543
        $result = $this->invoice->add_contact($contactid, $type, 'external');
544
545
        if (!$result) {
546
            throw new RestException(500, 'Error when added the contact');
547
        }
548
549
        return array(
550
            'success' => array(
551
                'code' => 200,
552
                'message' => 'Contact linked to the invoice'
553
            )
554
        );
555
    }
556
557
    /**
558
     * Delete a contact type of given invoice
559
     *
560
     * @param   int    $id             Id of invoice to update
561
     * @param   int    $contactid      Row key of the contact in the array contact_ids.
562
     * @param   string $type           Type of the contact (BILLING, SHIPPING, CUSTOMER).
563
     * @return  Object                 Object with cleaned properties
564
     *
565
     * @url DELETE {id}/contact/{contactid}/{type}
566
     *
567
     * @throws RestException 401
568
     * @throws RestException 404
569
     * @throws RestException 500 System error
570
     */
571
    public function deleteContact($id, $contactid, $type)
572
    {
573
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
574
            throw new RestException(403);
575
        }
576
577
        $result = $this->invoice->fetch($id);
578
579
        if (!$result) {
580
            throw new RestException(404, 'Invoice not found');
581
        }
582
583
        if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
584
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
585
        }
586
587
        $contacts = $this->invoice->liste_contact();
588
589
        foreach ($contacts as $contact) {
590
            if ($contact['id'] == $contactid && $contact['code'] == $type) {
591
                $result = $this->invoice->delete_contact($contact['rowid']);
592
593
                if (!$result) {
594
                    throw new RestException(500, 'Error when deleted the contact');
595
                }
596
            }
597
        }
598
599
        return $this->_cleanObjectDatas($this->invoice);
600
    }
601
602
    /**
603
     * Deletes a line of a given invoice
604
     *
605
     * @param   int   $id               Id of invoice
606
     * @param   int   $lineid           Id of the line to delete
607
     * @return  Object                  Object with cleaned properties
608
     *
609
     * @url     DELETE {id}/lines/{lineid}
610
     *
611
     * @throws RestException 400
612
     * @throws RestException 401
613
     * @throws RestException 404
614
     * @throws RestException 405
615
     */
616
    public function deleteLine($id, $lineid)
617
    {
618
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
619
            throw new RestException(403);
620
        }
621
        if (empty($lineid)) {
622
            throw new RestException(400, 'Line ID is mandatory');
623
        }
624
625
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
626
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
627
        }
628
629
        $result = $this->invoice->fetch($id);
630
        if (!$result) {
631
            throw new RestException(404, 'Invoice not found');
632
        }
633
634
        $updateRes = $this->invoice->deleteLine($lineid, $id);
635
        if ($updateRes > 0) {
636
            return $this->get($id);
637
        } else {
638
            throw new RestException(405, $this->invoice->error);
639
        }
640
    }
641
642
    /**
643
     * Update invoice
644
     *
645
     * @param   int             $id             Id of invoice to update
646
     * @param   array           $request_data   Datas
647
     * @return  Object|false                    Object with cleaned properties
648
     */
649
    public function put($id, $request_data = null)
650
    {
651
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
652
            throw new RestException(403);
653
        }
654
655
        $result = $this->invoice->fetch($id);
656
        if (!$result) {
657
            throw new RestException(404, 'Invoice not found');
658
        }
659
660
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
661
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
662
        }
663
664
        foreach ($request_data as $field => $value) {
665
            if ($field == 'id') {
666
                continue;
667
            }
668
            if ($field === 'caller') {
669
                // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
670
                $this->invoice->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
671
                continue;
672
            }
673
            if ($field == 'array_options' && is_array($value)) {
674
                foreach ($value as $index => $val) {
675
                    $this->invoice->array_options[$index] = $this->_checkValForAPI($field, $val, $this->invoice);
676
                }
677
                continue;
678
            }
679
680
            $this->invoice->$field = $this->_checkValForAPI($field, $value, $this->invoice);
681
682
            // If cond reglement => update date lim reglement
683
            if ($field == 'cond_reglement_id') {
684
                $this->invoice->date_lim_reglement = $this->invoice->calculate_date_lim_reglement();
685
            }
686
        }
687
688
        // update bank account
689
        if (!empty($this->invoice->fk_account)) {
690
            if ($this->invoice->setBankAccount($this->invoice->fk_account) == 0) {
691
                throw new RestException(400, $this->invoice->error);
692
            }
693
        }
694
695
        if ($this->invoice->update(DolibarrApiAccess::$user)) {
696
            return $this->get($id);
697
        }
698
699
        return false;
700
    }
701
702
    /**
703
     * Delete invoice
704
     *
705
     * @param   int     $id     Invoice ID
706
     * @return  array
707
     */
708
    public function delete($id)
709
    {
710
        if (!DolibarrApiAccess::$user->hasRight('facture', 'supprimer')) {
711
            throw new RestException(403);
712
        }
713
        $result = $this->invoice->fetch($id);
714
        if (!$result) {
715
            throw new RestException(404, 'Invoice not found');
716
        }
717
718
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
719
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
720
        }
721
722
        $result = $this->invoice->delete(DolibarrApiAccess::$user);
723
        if ($result < 0) {
724
            throw new RestException(500, 'Error when deleting invoice');
725
        } elseif ($result == 0) {
726
            throw new RestException(403, 'Invoice not erasable');
727
        }
728
729
        return array(
730
            'success' => array(
731
                'code' => 200,
732
                'message' => 'Invoice deleted'
733
            )
734
        );
735
    }
736
737
    /**
738
     * Add a line to a given invoice
739
     *
740
     * Example of POST query :
741
     * {
742
     *     "desc": "Desc", "subprice": "1.00000000", "qty": "1", "tva_tx": "20.000", "localtax1_tx": "0.000", "localtax2_tx": "0.000",
743
     *     "fk_product": "1", "remise_percent": "0", "date_start": "", "date_end": "", "fk_code_ventilation": 0,  "info_bits": "0",
744
     *     "fk_remise_except": null,  "product_type": "1", "rang": "-1", "special_code": "0", "fk_parent_line": null, "fk_fournprice": null,
745
     *     "pa_ht": "0.00000000", "label": "", "array_options": [], "situation_percent": "100", "fk_prev_id": null, "fk_unit": null
746
     * }
747
     *
748
     * @param int   $id             Id of invoice
749
     * @param array $request_data   InvoiceLine data
750
     *
751
     * @url     POST {id}/lines
752
     *
753
     * @return int
754
     *
755
     * @throws RestException 304
756
     * @throws RestException 401
757
     * @throws RestException 404
758
     * @throws RestException 400
759
     */
760
    public function postLine($id, $request_data = null)
761
    {
762
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
763
            throw new RestException(403);
764
        }
765
766
        $result = $this->invoice->fetch($id);
767
        if (!$result) {
768
            throw new RestException(404, 'Invoice not found');
769
        }
770
771
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
772
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
773
        }
774
775
        $request_data = (object) $request_data;
776
777
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
778
        $request_data->label = sanitizeVal($request_data->label);
779
780
        // Reset fk_parent_line for no child products and special product
781
        if (($request_data->product_type != 9 && empty($request_data->fk_parent_line)) || $request_data->product_type == 9) {
782
            $request_data->fk_parent_line = 0;
783
        }
784
785
        // calculate pa_ht
786
        $marginInfos = getMarginInfos($request_data->subprice, $request_data->remise_percent, $request_data->tva_tx, $request_data->localtax1_tx, $request_data->localtax2_tx, $request_data->fk_fournprice, $request_data->pa_ht);
787
        $pa_ht = $marginInfos[0];
788
789
        $updateRes = $this->invoice->addline(
790
            $request_data->desc,
791
            $request_data->subprice,
792
            $request_data->qty,
793
            $request_data->tva_tx,
794
            $request_data->localtax1_tx,
795
            $request_data->localtax2_tx,
796
            $request_data->fk_product,
797
            $request_data->remise_percent,
798
            $request_data->date_start,
799
            $request_data->date_end,
800
            $request_data->fk_code_ventilation,
801
            $request_data->info_bits,
802
            $request_data->fk_remise_except,
803
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
804
            $request_data->subprice,
805
            $request_data->product_type,
806
            $request_data->rang,
807
            $request_data->special_code,
808
            $request_data->origin,
809
            $request_data->origin_id,
810
            $request_data->fk_parent_line,
811
            empty($request_data->fk_fournprice) ? null : $request_data->fk_fournprice,
812
            $pa_ht,
813
            $request_data->label,
814
            $request_data->array_options,
815
            $request_data->situation_percent,
816
            $request_data->fk_prev_id,
817
            $request_data->fk_unit,
818
            0,
819
            $request_data->ref_ext
820
        );
821
822
        if ($updateRes < 0) {
823
            throw new RestException(400, 'Unable to insert the new line. Check your inputs. ' . $this->invoice->error);
824
        }
825
826
        return $updateRes;
827
    }
828
829
    /**
830
     * Adds a contact to an invoice
831
     *
832
     * @param   int     $id                 Order ID
833
     * @param   int     $fk_socpeople           Id of thirdparty contact (if source = 'external') or id of user (if source = 'internal') to link
834
     * @param   string  $type_contact           Type of contact (code). Must a code found into table llx_c_type_contact. For example: BILLING
835
     * @param   string  $source                 external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
836
     * @param   int     $notrigger              Disable all triggers
837
     *
838
     * @url POST    {id}/contacts
839
     *
840
     * @return  object
841
     *
842
     * @throws RestException 304
843
     * @throws RestException 401
844
     * @throws RestException 404
845
     * @throws RestException 500 System error
846
     *
847
     */
848
    public function addContact($id, $fk_socpeople, $type_contact, $source, $notrigger = 0)
849
    {
850
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
851
            throw new RestException(403);
852
        }
853
        $result = $this->invoice->fetch($id);
854
        if (!$result) {
855
            throw new RestException(404, 'Invoice not found');
856
        }
857
858
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
859
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
860
        }
861
862
        $result = $this->invoice->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
863
        if ($result < 0) {
864
            throw new RestException(500, 'Error : ' . $this->invoice->error);
865
        }
866
867
        $result = $this->invoice->fetch($id);
868
        if (!$result) {
869
            throw new RestException(404, 'Invoice not found');
870
        }
871
872
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
873
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
874
        }
875
876
        return $this->_cleanObjectDatas($this->invoice);
877
    }
878
879
880
881
    /**
882
     * Sets an invoice as draft
883
     *
884
     * @param   int $id             Order ID
885
     * @param   int $idwarehouse    Warehouse ID
886
     * @return  Object              Object with cleaned properties
887
     *
888
     * @url POST    {id}/settodraft
889
     *
890
     * @throws RestException 304
891
     * @throws RestException 401
892
     * @throws RestException 404
893
     * @throws RestException 500 System error
894
     *
895
     */
896
    public function settodraft($id, $idwarehouse = -1)
897
    {
898
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
899
            throw new RestException(403);
900
        }
901
        $result = $this->invoice->fetch($id);
902
        if (!$result) {
903
            throw new RestException(404, 'Invoice not found');
904
        }
905
906
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
907
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
908
        }
909
910
        $result = $this->invoice->setDraft(DolibarrApiAccess::$user, $idwarehouse);
911
        if ($result == 0) {
912
            throw new RestException(304, 'Nothing done.');
913
        }
914
        if ($result < 0) {
915
            throw new RestException(500, 'Error : ' . $this->invoice->error);
916
        }
917
918
        $result = $this->invoice->fetch($id);
919
        if (!$result) {
920
            throw new RestException(404, 'Invoice not found');
921
        }
922
923
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
924
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
925
        }
926
927
        return $this->_cleanObjectDatas($this->invoice);
928
    }
929
930
931
    /**
932
     * Validate an invoice
933
     *
934
     * If you get a bad value for param notrigger check that ou provide this in body
935
     * {
936
     *   "idwarehouse": 0,
937
     *   "notrigger": 0
938
     * }
939
     *
940
     * @param   int $id                 Invoice ID
941
     * @param   string $force_number    force ref invoice
942
     * @param   int $idwarehouse        Warehouse ID
943
     * @param   int $notrigger          1=Does not execute triggers, 0= execute triggers
944
     * @return  Object|false            Object with cleaned properties
945
     *
946
     * @url POST    {id}/validate
947
     */
948
    public function validate($id, $force_number = '', $idwarehouse = 0, $notrigger = 0)
949
    {
950
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
951
            throw new RestException(403);
952
        }
953
        $result = $this->invoice->fetch($id);
954
        if (!$result) {
955
            throw new RestException(404, 'Invoice not found');
956
        }
957
958
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
959
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
960
        }
961
962
        $result = $this->invoice->validate(DolibarrApiAccess::$user, $force_number, $idwarehouse, $notrigger);
963
        if ($result == 0) {
964
            throw new RestException(304, 'Error nothing done. May be object is already validated');
965
        }
966
        if ($result < 0) {
967
            throw new RestException(500, 'Error when validating Invoice: ' . $this->invoice->error);
968
        }
969
970
        $result = $this->invoice->fetch($id);
971
        if (!$result) {
972
            throw new RestException(404, 'Invoice not found');
973
        }
974
975
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
976
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
977
        }
978
979
        // copy from order
980
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
981
        $this->invoice->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $this->invoice->ref);
982
983
        return $this->_cleanObjectDatas($this->invoice);
984
    }
985
986
    /**
987
     * Sets an invoice as paid
988
     *
989
     * @param   int     $id            Order ID
990
     * @param   string  $close_code    Code filled if we classify to 'Paid completely' when payment is not complete (for escompte for example)
991
     * @param   string  $close_note    Comment defined if we classify to 'Paid' when payment is not complete (for escompte for example)
992
     * @return  Object                 Object with cleaned properties
993
     *
994
     * @url POST    {id}/settopaid
995
     *
996
     * @throws RestException 304
997
     * @throws RestException 401
998
     * @throws RestException 404
999
     * @throws RestException 500 System error
1000
     */
1001
    public function settopaid($id, $close_code = '', $close_note = '')
1002
    {
1003
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1004
            throw new RestException(403);
1005
        }
1006
        $result = $this->invoice->fetch($id);
1007
        if (!$result) {
1008
            throw new RestException(404, 'Invoice not found');
1009
        }
1010
1011
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1012
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1013
        }
1014
1015
        $result = $this->invoice->setPaid(DolibarrApiAccess::$user, $close_code, $close_note);
1016
        if ($result == 0) {
1017
            throw new RestException(304, 'Error nothing done. May be object is already validated');
1018
        }
1019
        if ($result < 0) {
1020
            throw new RestException(500, 'Error : ' . $this->invoice->error);
1021
        }
1022
1023
1024
        $result = $this->invoice->fetch($id);
1025
        if (!$result) {
1026
            throw new RestException(404, 'Invoice not found');
1027
        }
1028
1029
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1030
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1031
        }
1032
1033
        return $this->_cleanObjectDatas($this->invoice);
1034
    }
1035
1036
1037
    /**
1038
     * Sets an invoice as unpaid
1039
     *
1040
     * @param   int     $id             Order ID
1041
     * @return  Object                  Object with cleaned properties
1042
     *
1043
     * @url POST    {id}/settounpaid
1044
     *
1045
     * @throws RestException 304
1046
     * @throws RestException 401
1047
     * @throws RestException 404
1048
     * @throws RestException 500 System error
1049
     */
1050
    public function settounpaid($id)
1051
    {
1052
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1053
            throw new RestException(403);
1054
        }
1055
        $result = $this->invoice->fetch($id);
1056
        if (!$result) {
1057
            throw new RestException(404, 'Invoice not found');
1058
        }
1059
1060
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1061
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1062
        }
1063
1064
        $result = $this->invoice->setUnpaid(DolibarrApiAccess::$user);
1065
        if ($result == 0) {
1066
            throw new RestException(304, 'Nothing done');
1067
        }
1068
        if ($result < 0) {
1069
            throw new RestException(500, 'Error : ' . $this->invoice->error);
1070
        }
1071
1072
1073
        $result = $this->invoice->fetch($id);
1074
        if (!$result) {
1075
            throw new RestException(404, 'Invoice not found');
1076
        }
1077
1078
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1079
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1080
        }
1081
1082
        return $this->_cleanObjectDatas($this->invoice);
1083
    }
1084
1085
    /**
1086
     * Get discount from invoice
1087
     *
1088
     * @param int   $id             Id of invoice
1089
     * @return  Object              Object with cleaned properties
1090
     *
1091
     * @url GET {id}/discount
1092
     */
1093
    public function getDiscount($id)
1094
    {
1095
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1096
1097
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1098
            throw new RestException(403);
1099
        }
1100
1101
        $result = $this->invoice->fetch($id);
1102
        if (!$result) {
1103
            throw new RestException(404, 'Invoice not found');
1104
        }
1105
1106
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1107
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1108
        }
1109
1110
        $discountcheck = new DiscountAbsolute($this->db);
1111
        $result = $discountcheck->fetch(0, $this->invoice->id);
1112
1113
        if ($result == 0) {
1114
            throw new RestException(404, 'Discount not found');
1115
        }
1116
        if ($result < 0) {
1117
            throw new RestException(500, $discountcheck->error);
1118
        }
1119
1120
        return parent::_cleanObjectDatas($discountcheck);
1121
    }
1122
1123
    /**
1124
     * Create a discount (credit available) for a credit note or a deposit.
1125
     *
1126
     * @param   int     $id             Invoice ID
1127
     * @return  Object                  Object with cleaned properties
1128
     *
1129
     * @url POST    {id}/markAsCreditAvailable
1130
     *
1131
     * @throws RestException 304
1132
     * @throws RestException 401
1133
     * @throws RestException 404
1134
     * @throws RestException 500 System error
1135
     */
1136
    public function markAsCreditAvailable($id)
1137
    {
1138
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1139
1140
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1141
            throw new RestException(403);
1142
        }
1143
1144
        $result = $this->invoice->fetch($id);
1145
        if (!$result) {
1146
            throw new RestException(404, 'Invoice not found');
1147
        }
1148
1149
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1150
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1151
        }
1152
1153
        if ($this->invoice->paye) {
1154
            throw new RestException(500, 'Alreay paid');
1155
        }
1156
1157
        $this->invoice->fetch($id);
1158
        $this->invoice->fetch_thirdparty();
1159
1160
        // Check if there is already a discount (protection to avoid duplicate creation when resubmit post)
1161
        $discountcheck = new DiscountAbsolute($this->db);
1162
        $result = $discountcheck->fetch(0, $this->invoice->id);
1163
1164
        $canconvert = 0;
1165
        if ($this->invoice->type == Facture::TYPE_DEPOSIT && empty($discountcheck->id)) {
1166
            $canconvert = 1; // we can convert deposit into discount if deposit is paid (completely, partially or not at all) and not already converted (see real condition into condition used to show button converttoreduc)
1167
        }
1168
        if (($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_STANDARD) && $this->invoice->paye == 0 && empty($discountcheck->id)) {
1169
            $canconvert = 1; // we can convert credit note into discount if credit note is not paid back and not already converted and amount of payment is 0 (see real condition into condition used to show button converttoreduc)
1170
        }
1171
        if ($canconvert) {
1172
            $this->db->begin();
1173
1174
            $amount_ht = $amount_tva = $amount_ttc = array();
1175
            $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
1176
1177
            // Loop on each vat rate
1178
            $i = 0;
1179
            foreach ($this->invoice->lines as $line) {
1180
                if ($line->product_type < 9 && $line->total_ht != 0) { // Remove lines with product_type greater than or equal to 9
1181
                    // no need to create discount if amount is null
1182
                    $amount_ht[$line->tva_tx] += $line->total_ht;
1183
                    $amount_tva[$line->tva_tx] += $line->total_tva;
1184
                    $amount_ttc[$line->tva_tx] += $line->total_ttc;
1185
                    $multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht;
1186
                    $multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva;
1187
                    $multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc;
1188
                    $i++;
1189
                }
1190
            }
1191
1192
            // Insert one discount by VAT rate category
1193
            $discount = new DiscountAbsolute($this->db);
1194
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1195
                $discount->description = '(CREDIT_NOTE)';
1196
            } elseif ($this->invoice->type == Facture::TYPE_DEPOSIT) {
1197
                $discount->description = '(DEPOSIT)';
1198
            } elseif ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1199
                $discount->description = '(EXCESS RECEIVED)';
1200
            } else {
1201
                throw new RestException(500, 'Cant convert to reduc an Invoice of this type');
1202
            }
1203
1204
            $discount->fk_soc = $this->invoice->socid;
1205
            $discount->socid = $this->invoice->socid;
1206
            $discount->fk_facture_source = $this->invoice->id;
1207
1208
            $error = 0;
1209
1210
            if ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1211
                // If we're on a standard invoice, we have to get excess received to create a discount in TTC without VAT
1212
1213
                // Total payments
1214
                $sql = 'SELECT SUM(pf.amount) as total_payments';
1215
                $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement_facture as pf, ' . MAIN_DB_PREFIX . 'paiement as p';
1216
                $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as c ON p.fk_paiement = c.id';
1217
                $sql .= ' WHERE pf.fk_facture = ' . ((int) $this->invoice->id);
1218
                $sql .= ' AND pf.fk_paiement = p.rowid';
1219
                $sql .= ' AND p.entity IN (' . getEntity('invoice') . ')';
1220
                $resql = $this->db->query($sql);
1221
                if (!$resql) {
1222
                    dol_print_error($this->db);
1223
                }
1224
1225
                $res = $this->db->fetch_object($resql);
1226
                $total_payments = $res->total_payments;
1227
1228
                // Total credit note and deposit
1229
                $total_creditnote_and_deposit = 0;
1230
                $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1231
                $sql .= " re.description, re.fk_facture_source";
1232
                $sql .= " FROM " . MAIN_DB_PREFIX . "societe_remise_except as re";
1233
                $sql .= " WHERE fk_facture = " . ((int) $this->invoice->id);
1234
                $resql = $this->db->query($sql);
1235
                if (!empty($resql)) {
1236
                    while ($obj = $this->db->fetch_object($resql)) {
1237
                        $total_creditnote_and_deposit += $obj->amount_ttc;
1238
                    }
1239
                } else {
1240
                    dol_print_error($this->db);
1241
                }
1242
1243
                $discount->amount_ht = $discount->amount_ttc = $total_payments + $total_creditnote_and_deposit - $this->invoice->total_ttc;
1244
                $discount->amount_tva = 0;
1245
                $discount->tva_tx = 0;
1246
1247
                $result = $discount->create(DolibarrApiAccess::$user);
1248
                if ($result < 0) {
1249
                    $error++;
1250
                }
1251
            }
1252
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_DEPOSIT) {
1253
                foreach ($amount_ht as $tva_tx => $xxx) {
1254
                    $discount->amount_ht = abs($amount_ht[$tva_tx]);
1255
                    $discount->amount_tva = abs($amount_tva[$tva_tx]);
1256
                    $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
1257
                    $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
1258
                    $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
1259
                    $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
1260
                    $discount->tva_tx = abs($tva_tx);
1261
1262
                    $result = $discount->create(DolibarrApiAccess::$user);
1263
                    if ($result < 0) {
1264
                        $error++;
1265
                        break;
1266
                    }
1267
                }
1268
            }
1269
1270
            if (empty($error)) {
1271
                if ($this->invoice->type != Facture::TYPE_DEPOSIT) {
1272
                    // Set the invoice as paid
1273
                    $result = $this->invoice->setPaid(DolibarrApiAccess::$user);
1274
                    if ($result >= 0) {
1275
                        $this->db->commit();
1276
                    } else {
1277
                        $this->db->rollback();
1278
                        throw new RestException(500, 'Could not set paid');
1279
                    }
1280
                } else {
1281
                    $this->db->commit();
1282
                }
1283
            } else {
1284
                $this->db->rollback();
1285
                throw new RestException(500, 'Discount creation error');
1286
            }
1287
        }
1288
1289
        return $this->_cleanObjectDatas($this->invoice);
1290
    }
1291
1292
    /**
1293
     * Add a discount line into an invoice (as an invoice line) using an existing absolute discount
1294
     *
1295
     * Note that this consume the discount.
1296
     *
1297
     * @param int   $id             Id of invoice
1298
     * @param int   $discountid     Id of discount
1299
     * @return int
1300
     *
1301
     * @url     POST {id}/usediscount/{discountid}
1302
     *
1303
     * @throws RestException 400
1304
     * @throws RestException 401
1305
     * @throws RestException 404
1306
     * @throws RestException 405
1307
     */
1308
    public function useDiscount($id, $discountid)
1309
    {
1310
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1311
            throw new RestException(403);
1312
        }
1313
        if (empty($id)) {
1314
            throw new RestException(400, 'Invoice ID is mandatory');
1315
        }
1316
        if (empty($discountid)) {
1317
            throw new RestException(400, 'Discount ID is mandatory');
1318
        }
1319
1320
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1321
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1322
        }
1323
1324
        $result = $this->invoice->fetch($id);
1325
        if (!$result) {
1326
            throw new RestException(404, 'Invoice not found');
1327
        }
1328
1329
        $result = $this->invoice->insert_discount($discountid);
1330
        if ($result < 0) {
1331
            throw new RestException(405, $this->invoice->error);
1332
        }
1333
1334
        return $result;
1335
    }
1336
1337
    /**
1338
     * Add an available credit note discount to payments of an existing invoice.
1339
     *
1340
     *  Note that this consume the credit note.
1341
     *
1342
     * @param int   $id            Id of invoice
1343
     * @param int   $discountid    Id of a discount coming from a credit note
1344
     * @return  int
1345
     *
1346
     * @url     POST {id}/usecreditnote/{discountid}
1347
     *
1348
     * @throws RestException 400
1349
     * @throws RestException 401
1350
     * @throws RestException 404
1351
     * @throws RestException 405
1352
     */
1353
    public function useCreditNote($id, $discountid)
1354
    {
1355
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1356
1357
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1358
            throw new RestException(403);
1359
        }
1360
        if (empty($id)) {
1361
            throw new RestException(400, 'Invoice ID is mandatory');
1362
        }
1363
        if (empty($discountid)) {
1364
            throw new RestException(400, 'Credit ID is mandatory');
1365
        }
1366
1367
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1368
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1369
        }
1370
        $discount = new DiscountAbsolute($this->db);
1371
        $result = $discount->fetch($discountid);
1372
        if (!$result) {
1373
            throw new RestException(404, 'Credit not found');
1374
        }
1375
1376
        $result = $discount->link_to_invoice(0, $id);
1377
        if ($result < 0) {
1378
            throw new RestException(405, $discount->error);
1379
        }
1380
1381
        return $result;
1382
    }
1383
1384
    /**
1385
     * Get list of payments of a given invoice
1386
     *
1387
     * @param   int   $id             Id of invoice
1388
     * @return  array
1389
     *
1390
     * @url     GET {id}/payments
1391
     *
1392
     * @throws RestException 400
1393
     * @throws RestException 401
1394
     * @throws RestException 404
1395
     * @throws RestException 405
1396
     */
1397
    public function getPayments($id)
1398
    {
1399
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1400
            throw new RestException(403);
1401
        }
1402
        if (empty($id)) {
1403
            throw new RestException(400, 'Invoice ID is mandatory');
1404
        }
1405
1406
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1407
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1408
        }
1409
1410
        $result = $this->invoice->fetch($id);
1411
        if (!$result) {
1412
            throw new RestException(404, 'Invoice not found');
1413
        }
1414
1415
        $result = $this->invoice->getListOfPayments();
1416
        if ($result < 0) {
1417
            throw new RestException(405, $this->invoice->error);
1418
        }
1419
1420
        return $result;
1421
    }
1422
1423
1424
    /**
1425
     * Add payment line to a specific invoice with the remain to pay as amount.
1426
     *
1427
     * @param int     $id                               Id of invoice
1428
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1429
     * @param int     $paymentid          {@from body}  Payment mode Id {@min 1}
1430
     * @param string  $closepaidinvoices  {@from body}  Close paid invoices {@choice yes,no}
1431
     * @param int     $accountid          {@from body}  Account Id {@min 1}
1432
     * @param string  $num_payment        {@from body}  Payment number (optional)
1433
     * @param string  $comment            {@from body}  Note private (optional)
1434
     * @param string  $chqemetteur        {@from body}  Payment issuer (mandatory if paymentcode = 'CHQ')
1435
     * @param string  $chqbank            {@from body}  Issuer bank name (optional)
1436
     *
1437
     * @url     POST {id}/payments
1438
     *
1439
     * @return int  Payment ID
1440
     *
1441
     * @throws RestException 400
1442
     * @throws RestException 401
1443
     * @throws RestException 404
1444
     */
1445
    public function addPayment($id, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '')
1446
    {
1447
1448
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1449
            throw new RestException(403);
1450
        }
1451
        if (empty($id)) {
1452
            throw new RestException(400, 'Invoice ID is mandatory');
1453
        }
1454
1455
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1456
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1457
        }
1458
1459
        if (isModEnabled("bank")) {
1460
            if (empty($accountid)) {
1461
                throw new RestException(400, 'Account ID is mandatory');
1462
            }
1463
        }
1464
1465
        if (empty($paymentid)) {
1466
            throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1467
        }
1468
1469
1470
        $result = $this->invoice->fetch($id);
1471
        if (!$result) {
1472
            throw new RestException(404, 'Invoice not found');
1473
        }
1474
1475
        // Calculate amount to pay
1476
        $totalpaid = $this->invoice->getSommePaiement();
1477
        $totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
1478
        $totaldeposits = $this->invoice->getSumDepositsUsed();
1479
        $resteapayer = price2num($this->invoice->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1480
1481
        $this->db->begin();
1482
1483
        $amounts = array();
1484
        $multicurrency_amounts = array();
1485
1486
        // Clean parameters amount if payment is for a credit note
1487
        if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1488
            $resteapayer = price2num($resteapayer, 'MT');
1489
            $amounts[$id] = (float) price2num(-1 * (float) $resteapayer, 'MT');
1490
            // Multicurrency
1491
            $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1492
            $multicurrency_amounts[$id] = (float) price2num(-1 * (float) $newvalue, 'MT');
1493
        } else {
1494
            $resteapayer = price2num($resteapayer, 'MT');
1495
            $amounts[$id] = (float) $resteapayer;
1496
            // Multicurrency
1497
            $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1498
            $multicurrency_amounts[$id] = (float) $newvalue;
1499
        }
1500
1501
        // Creation of payment line
1502
        $paymentobj = new Paiement($this->db);
1503
        $paymentobj->datepaye     = dol_stringtotime($datepaye);
1504
        $paymentobj->amounts      = $amounts; // Array with all payments dispatching with invoice id
1505
        $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1506
        $paymentobj->paiementid = $paymentid;
1507
        $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1508
        $paymentobj->num_payment = $num_payment;
1509
        $paymentobj->note_private = $comment;
1510
1511
        $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1512
        if ($payment_id < 0) {
1513
            $this->db->rollback();
1514
            throw new RestException(400, 'Payment error : ' . $paymentobj->error);
1515
        }
1516
1517
        if (isModEnabled("bank")) {
1518
            $label = '(CustomerInvoicePayment)';
1519
1520
            if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1521
                throw new RestException(400, 'Emetteur is mandatory when payment code is ' . $paymentobj->paiementcode);
1522
            }
1523
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1524
                $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1525
            }
1526
            $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1527
            if ($result < 0) {
1528
                $this->db->rollback();
1529
                throw new RestException(400, 'Add payment to bank error : ' . $paymentobj->error);
1530
            }
1531
        }
1532
1533
        $this->db->commit();
1534
1535
        return $payment_id;
1536
    }
1537
1538
    /**
1539
     * Add a payment to pay partially or completely one or several invoices.
1540
     * Warning: Take care that all invoices are owned by the same customer.
1541
     * Example of value for parameter arrayofamounts: {"1": {"amount": "99.99", "multicurrency_amount": ""}, "2": {"amount": "", "multicurrency_amount": "10"}}
1542
     *
1543
     * @param array   $arrayofamounts     {@from body}  Array with id of invoices with amount to pay for each invoice
1544
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1545
     * @param int     $paymentid           {@from body}  Payment mode Id {@min 1}
1546
     * @param string  $closepaidinvoices   {@from body}  Close paid invoices {@choice yes,no}
1547
     * @param int     $accountid           {@from body}  Account Id {@min 1}
1548
     * @param string  $num_payment         {@from body}  Payment number (optional)
1549
     * @param string  $comment             {@from body}  Note private (optional)
1550
     * @param string  $chqemetteur         {@from body}  Payment issuer (mandatory if paiementcode = 'CHQ')
1551
     * @param string  $chqbank             {@from body}  Issuer bank name (optional)
1552
     * @param string  $ref_ext             {@from body}  External reference (optional)
1553
     * @param bool    $accepthigherpayment {@from body}  Accept higher payments that it remains to be paid (optional)
1554
     *
1555
     * @url     POST /paymentsdistributed
1556
     *
1557
     * @return int  Payment ID
1558
     *
1559
     * @throws RestException 400
1560
     * @throws RestException 401
1561
     * @throws RestException 403
1562
     * @throws RestException 404
1563
     */
1564
    public function addPaymentDistributed($arrayofamounts, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '', $ref_ext = '', $accepthigherpayment = false)
1565
    {
1566
1567
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1568
            throw new RestException(403);
1569
        }
1570
        foreach ($arrayofamounts as $id => $amount) {
1571
            if (empty($id)) {
1572
                throw new RestException(400, 'Invoice ID is mandatory. Fill the invoice id and amount into arrayofamounts parameter. For example: {"1": "99.99", "2": "10"}');
1573
            }
1574
            if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1575
                throw new RestException(403, 'Access not allowed on invoice ID ' . $id . ' for login ' . DolibarrApiAccess::$user->login);
1576
            }
1577
        }
1578
1579
        if (isModEnabled("bank")) {
1580
            if (empty($accountid)) {
1581
                throw new RestException(400, 'Account ID is mandatory');
1582
            }
1583
        }
1584
        if (empty($paymentid)) {
1585
            throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1586
        }
1587
1588
        $this->db->begin();
1589
1590
        $amounts = array();
1591
        $multicurrency_amounts = array();
1592
1593
        // Loop on each invoice to pay
1594
        foreach ($arrayofamounts as $id => $amountarray) {
1595
            $result = $this->invoice->fetch($id);
1596
            if (!$result) {
1597
                $this->db->rollback();
1598
                throw new RestException(404, 'Invoice ID ' . $id . ' not found');
1599
            }
1600
1601
            if (($amountarray["amount"] == "remain" || $amountarray["amount"] > 0) && ($amountarray["multicurrency_amount"] == "remain" || $amountarray["multicurrency_amount"] > 0)) {
1602
                $this->db->rollback();
1603
                throw new RestException(400, 'Payment in both currency ' . $id . ' ( amount: ' . $amountarray["amount"] . ', multicurrency_amount: ' . $amountarray["multicurrency_amount"] . ')');
1604
            }
1605
1606
            $is_multicurrency = 0;
1607
            $total_ttc = $this->invoice->total_ttc;
1608
1609
            if ($amountarray["multicurrency_amount"] > 0 || $amountarray["multicurrency_amount"] == "remain") {
1610
                $is_multicurrency = 1;
1611
                $total_ttc = $this->invoice->multicurrency_total_ttc;
1612
            }
1613
1614
            // Calculate amount to pay
1615
            $totalpaid = $this->invoice->getSommePaiement($is_multicurrency);
1616
            $totalcreditnotes = $this->invoice->getSumCreditNotesUsed($is_multicurrency);
1617
            $totaldeposits = $this->invoice->getSumDepositsUsed($is_multicurrency);
1618
            $remainstopay = $amount = price2num($total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1619
1620
            if (!$is_multicurrency && $amountarray["amount"] != 'remain') {
1621
                $amount = price2num($amountarray["amount"], 'MT');
1622
            }
1623
1624
            if ($is_multicurrency && $amountarray["multicurrency_amount"] != 'remain') {
1625
                $amount = price2num($amountarray["multicurrency_amount"], 'MT');
1626
            }
1627
1628
            if ($amount > $remainstopay && !$accepthigherpayment) {
1629
                $this->db->rollback();
1630
                throw new RestException(400, 'Payment amount on invoice ID ' . $id . ' (' . $amount . ') is higher than remain to pay (' . $remainstopay . ')');
1631
            }
1632
1633
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1634
                $amount = price2num(-1 * (float) $amount, 'MT');
1635
            }
1636
1637
            if ($is_multicurrency) {
1638
                $amounts[$id] = null;
1639
                // Multicurrency
1640
                $multicurrency_amounts[$id] = (float) $amount;
1641
            } else {
1642
                $amounts[$id] = (float) $amount;
1643
                // Multicurrency
1644
                $multicurrency_amounts[$id] = null;
1645
            }
1646
        }
1647
1648
        // Creation of payment line
1649
        $paymentobj = new Paiement($this->db);
1650
        $paymentobj->datepaye     = $datepaye;
1651
        $paymentobj->amounts      = $amounts; // Array with all payments dispatching with invoice id
1652
        $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1653
        $paymentobj->paiementid   = $paymentid;
1654
        $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1655
        $paymentobj->num_payment  = $num_payment;
1656
        $paymentobj->note_private = $comment;
1657
        $paymentobj->ref_ext      = $ref_ext;
1658
        $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1659
        if ($payment_id < 0) {
1660
            $this->db->rollback();
1661
            throw new RestException(400, 'Payment error : ' . $paymentobj->error);
1662
        }
1663
        if (isModEnabled("bank")) {
1664
            $label = '(CustomerInvoicePayment)';
1665
            if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1666
                throw new RestException(400, 'Emetteur is mandatory when payment code is ' . $paymentobj->paiementcode);
1667
            }
1668
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1669
                $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1670
            }
1671
            $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1672
            if ($result < 0) {
1673
                $this->db->rollback();
1674
                throw new RestException(400, 'Add payment to bank error : ' . $paymentobj->error);
1675
            }
1676
        }
1677
1678
        $this->db->commit();
1679
1680
        return $payment_id;
1681
    }
1682
1683
    /**
1684
     * Update a payment
1685
     *
1686
     * @param int       $id             Id of payment
1687
     * @param string    $num_payment    Payment number
1688
     *
1689
     * @url     PUT payments/{id}
1690
     *
1691
     * @return array
1692
     *
1693
     * @throws RestException 400 Bad parameters
1694
     * @throws RestException 401 Not allowed
1695
     * @throws RestException 404 Not found
1696
     */
1697
    public function putPayment($id, $num_payment = '')
1698
    {
1699
1700
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1701
            throw new RestException(403);
1702
        }
1703
        if (empty($id)) {
1704
            throw new RestException(400, 'Payment ID is mandatory');
1705
        }
1706
1707
        $paymentobj = new Paiement($this->db);
1708
        $result = $paymentobj->fetch($id);
1709
1710
        if (!$result) {
1711
            throw new RestException(404, 'Payment not found');
1712
        }
1713
1714
        if (!empty($num_payment)) {
1715
            $result = $paymentobj->update_num($num_payment);
1716
            if ($result < 0) {
1717
                throw new RestException(500, 'Error when updating the payment num');
1718
            }
1719
        }
1720
1721
        return [
1722
            'success' => [
1723
                'code' => 200,
1724
                'message' => 'Payment updated'
1725
            ]
1726
        ];
1727
    }
1728
1729
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1730
    /**
1731
     * Clean sensible object datas
1732
     *
1733
     * @param   Object  $object     Object to clean
1734
     * @return  Object              Object with cleaned properties
1735
     */
1736
    protected function _cleanObjectDatas($object)
1737
    {
1738
		// phpcs:enable
1739
        $object = parent::_cleanObjectDatas($object);
1740
1741
        unset($object->note);
1742
        unset($object->address);
1743
        unset($object->barcode_type);
1744
        unset($object->barcode_type_code);
1745
        unset($object->barcode_type_label);
1746
        unset($object->barcode_type_coder);
1747
        unset($object->canvas);
1748
1749
        return $object;
1750
    }
1751
1752
    /**
1753
     * Validate fields before create or update object
1754
     *
1755
     * @param   array|null    $data       Datas to validate
1756
     * @return  array
1757
     *
1758
     * @throws RestException
1759
     */
1760
    private function _validate($data)
1761
    {
1762
        $invoice = array();
1763
        foreach (Invoices::$FIELDS as $field) {
1764
            if (!isset($data[$field])) {
1765
                throw new RestException(400, "$field field missing");
1766
            }
1767
            $invoice[$field] = $data[$field];
1768
        }
1769
        return $invoice;
1770
    }
1771
1772
1773
    /**
1774
     * Get properties of a template invoice object
1775
     *
1776
     * Return an array with invoice information
1777
     *
1778
     * @param   int     $id             ID of template invoice
1779
     * @param   int     $contact_list   0:Return array contains all properties, 1:Return array contains just id, -1: Do not return contacts/adddesses
1780
     * @return  Object                  Object with cleaned properties
1781
     *
1782
     * @url GET    templates/{id}
1783
     *
1784
     * @throws  RestException
1785
     */
1786
    public function getTemplateInvoice($id, $contact_list = 1)
1787
    {
1788
        return $this->_fetchTemplateInvoice($id, '', '', $contact_list);
1789
    }
1790
1791
    /**
1792
     * Get properties of an invoice object
1793
     *
1794
     * Return an array with invoice information
1795
     *
1796
     * @param   int         $id             ID of order
1797
     * @param   string      $ref            Ref of object
1798
     * @param   string      $ref_ext        External reference of object
1799
     * @param   int         $contact_list   0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id, -1: Do not return contacts/adddesses
1800
     * @return  Object                      Object with cleaned properties
1801
     *
1802
     * @throws  RestException
1803
     */
1804
    private function _fetchTemplateInvoice($id, $ref = '', $ref_ext = '', $contact_list = 1)
1805
    {
1806
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1807
            throw new RestException(403);
1808
        }
1809
1810
        $result = $this->template_invoice->fetch($id, $ref, $ref_ext);
1811
        if (!$result) {
1812
            throw new RestException(404, 'Template invoice not found');
1813
        }
1814
1815
        if (!DolibarrApi::_checkAccessToResource('facturerec', $this->template_invoice->id)) {
1816
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1817
        }
1818
1819
        // Add external contacts ids
1820
        if ($contact_list > -1) {
1821
            $tmparray = $this->template_invoice->liste_contact(-1, 'external', $contact_list);
1822
            if (is_array($tmparray)) {
1823
                $this->template_invoice->contacts_ids = $tmparray;
1824
            }
1825
        }
1826
1827
        $this->template_invoice->fetchObjectLinked();
1828
        return $this->_cleanTemplateObjectDatas($this->template_invoice);
1829
    }
1830
1831
1832
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1833
    /**
1834
     * Clean sensible object datas
1835
     *
1836
     * @param   Object  $object     Object to clean
1837
     * @return  Object              Object with cleaned properties
1838
     */
1839
    protected function _cleanTemplateObjectDatas($object)
1840
    {
1841
		// phpcs:enable
1842
        $object = parent::_cleanObjectDatas($object);
1843
1844
        unset($object->note);
1845
        unset($object->address);
1846
        unset($object->barcode_type);
1847
        unset($object->barcode_type_code);
1848
        unset($object->barcode_type_label);
1849
        unset($object->barcode_type_coder);
1850
        unset($object->canvas);
1851
1852
        return $object;
1853
    }
1854
}
1855