Passed
Push — EXTRACT_CLASSES ( a2ff75...ae6b5c )
by Rafael
34:15
created

Invoices::markAsCreditAvailable()   F

Complexity

Conditions 34
Paths 1740

Size

Total Lines 154
Code Lines 102

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 34
eloc 102
nc 1740
nop 1
dl 0
loc 154
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 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 Luracast\Restler\RestException;
25
26
require_once constant('DOL_DOCUMENT_ROOT') . '/compta/facture/class/facture.class.php';
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
        use Dolibarr\Code\Adherents\Classes\Adherent;
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_USE on line 344 at column 8
Loading history...
345
346
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
347
            throw new RestException(403);
348
        }
349
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
350
            throw new RestException(403);
351
        }
352
        if (empty($orderid)) {
353
            throw new RestException(400, 'Order ID is mandatory');
354
        }
355
356
        $order = new Commande($this->db);
357
        $result = $order->fetch($orderid);
358
        if (!$result) {
359
            throw new RestException(404, 'Order not found');
360
        }
361
362
        $result = $this->invoice->createFromOrder($order, DolibarrApiAccess::$user);
363
        if ($result < 0) {
364
            throw new RestException(405, $this->invoice->error);
365
        }
366
        $this->invoice->fetchObjectLinked();
367
        return $this->_cleanObjectDatas($this->invoice);
368
    }
369
370
    /**
371
    * Create an invoice using a contract.
372
    *
373
    * @param int   $contractid       Id of the contract
374
    * @return     Object                          Object with cleaned properties
375
    *
376
    * @url     POST /createfromcontract/{contractid}
377
    *
378
    * @throws RestException 400
379
    * @throws RestException 401
380
    * @throws RestException 404
381
    * @throws RestException 405
382
    */
383
    public function createInvoiceFromContract($contractid)
384
    {
385
        require_once constant('DOL_DOCUMENT_ROOT') . '/contrat/class/contrat.class.php';
386
387
        if (!DolibarrApiAccess::$user->hasRight('contrat', 'lire')) {
388
            throw new RestException(403);
389
        }
390
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
391
            throw new RestException(403);
392
        }
393
        if (empty($contractid)) {
394
            throw new RestException(400, 'Contract ID is mandatory');
395
        }
396
397
        $contract = new Contrat($this->db);
398
        $result = $contract->fetch($contractid);
399
        if (!$result) {
400
            throw new RestException(404, 'Contract not found');
401
        }
402
403
        $result = $this->invoice->createFromContract($contract, DolibarrApiAccess::$user);
404
        if ($result < 0) {
405
            throw new RestException(405, $this->invoice->error);
406
        }
407
        $this->invoice->fetchObjectLinked();
408
        return $this->_cleanObjectDatas($this->invoice);
409
    }
410
411
    /**
412
     * Get lines of an invoice
413
     *
414
     * @param   int   $id               Id of invoice
415
     * @return  array                   Array of lines
416
     *
417
     * @url GET {id}/lines
418
     */
419
    public function getLines($id)
420
    {
421
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
422
            throw new RestException(403);
423
        }
424
425
        $result = $this->invoice->fetch($id);
426
        if (!$result) {
427
            throw new RestException(404, 'Invoice not found');
428
        }
429
430
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
431
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
432
        }
433
        $this->invoice->getLinesArray();
434
        $result = array();
435
        foreach ($this->invoice->lines as $line) {
436
            array_push($result, $this->_cleanObjectDatas($line));
437
        }
438
        return $result;
439
    }
440
441
    /**
442
     * Update a line to a given invoice
443
     *
444
     * @param   int   $id             Id of invoice to update
445
     * @param   int   $lineid         Id of line to update
446
     * @param   array $request_data   InvoiceLine data
447
     * @return  Object                Object with cleaned properties
448
     *
449
     * @url PUT {id}/lines/{lineid}
450
     *
451
     * @throws RestException 304
452
     * @throws RestException 401
453
     * @throws RestException 404 Invoice not found
454
     */
455
    public function putLine($id, $lineid, $request_data = null)
456
    {
457
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
458
            throw new RestException(403);
459
        }
460
461
        $result = $this->invoice->fetch($id);
462
        if (!$result) {
463
            throw new RestException(404, 'Invoice not found');
464
        }
465
466
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
467
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
468
        }
469
470
        $request_data = (object) $request_data;
471
472
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
473
        $request_data->label = sanitizeVal($request_data->label);
474
475
        $updateRes = $this->invoice->updateline(
476
            $lineid,
477
            $request_data->desc,
478
            $request_data->subprice,
479
            $request_data->qty,
480
            $request_data->remise_percent,
481
            $request_data->date_start,
482
            $request_data->date_end,
483
            $request_data->tva_tx,
484
            $request_data->localtax1_tx,
485
            $request_data->localtax2_tx,
486
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
487
            $request_data->info_bits,
488
            $request_data->product_type,
489
            $request_data->fk_parent_line,
490
            0,
491
            $request_data->fk_fournprice,
492
            $request_data->pa_ht,
493
            $request_data->label,
494
            $request_data->special_code,
495
            $request_data->array_options,
496
            $request_data->situation_percent,
497
            $request_data->fk_unit,
498
            $request_data->multicurrency_subprice,
499
            0,
500
            $request_data->ref_ext,
501
            $request_data->rang
502
        );
503
504
        if ($updateRes > 0) {
505
            $result = $this->get($id);
506
            unset($result->line);
507
            return $this->_cleanObjectDatas($result);
508
        } else {
509
            throw new RestException(304, $this->invoice->error);
510
        }
511
    }
512
513
    /**
514
     * Add a contact type of given invoice
515
     *
516
     * @param   int    $id             Id of invoice to update
517
     * @param   int    $contactid      Id of contact to add
518
     * @param   string $type           Type of the contact (BILLING, SHIPPING, CUSTOMER)
519
     * @return  array
520
     *
521
     * @url POST {id}/contact/{contactid}/{type}
522
     *
523
     * @throws RestException 401
524
     * @throws RestException 404
525
     */
526
    public function postContact($id, $contactid, $type)
527
    {
528
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
529
            throw new RestException(403);
530
        }
531
532
        $result = $this->invoice->fetch($id);
533
534
        if (!$result) {
535
            throw new RestException(404, 'Invoice not found');
536
        }
537
538
        if (!in_array($type, array('BILLING', 'SHIPPING', 'CUSTOMER'), true)) {
539
            throw new RestException(500, 'Availables types: BILLING, SHIPPING OR CUSTOMER');
540
        }
541
542
        if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
543
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
544
        }
545
546
        $result = $this->invoice->add_contact($contactid, $type, 'external');
547
548
        if (!$result) {
549
            throw new RestException(500, 'Error when added the contact');
550
        }
551
552
        return array(
553
            'success' => array(
554
                'code' => 200,
555
                'message' => 'Contact linked to the invoice'
556
            )
557
        );
558
    }
559
560
    /**
561
     * Delete a contact type of given invoice
562
     *
563
     * @param   int    $id             Id of invoice to update
564
     * @param   int    $contactid      Row key of the contact in the array contact_ids.
565
     * @param   string $type           Type of the contact (BILLING, SHIPPING, CUSTOMER).
566
     * @return  Object                 Object with cleaned properties
567
     *
568
     * @url DELETE {id}/contact/{contactid}/{type}
569
     *
570
     * @throws RestException 401
571
     * @throws RestException 404
572
     * @throws RestException 500 System error
573
     */
574
    public function deleteContact($id, $contactid, $type)
575
    {
576
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
577
            throw new RestException(403);
578
        }
579
580
        $result = $this->invoice->fetch($id);
581
582
        if (!$result) {
583
            throw new RestException(404, 'Invoice not found');
584
        }
585
586
        if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
587
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
588
        }
589
590
        $contacts = $this->invoice->liste_contact();
591
592
        foreach ($contacts as $contact) {
593
            if ($contact['id'] == $contactid && $contact['code'] == $type) {
594
                $result = $this->invoice->delete_contact($contact['rowid']);
595
596
                if (!$result) {
597
                    throw new RestException(500, 'Error when deleted the contact');
598
                }
599
            }
600
        }
601
602
        return $this->_cleanObjectDatas($this->invoice);
603
    }
604
605
    /**
606
     * Deletes a line of a given invoice
607
     *
608
     * @param   int   $id               Id of invoice
609
     * @param   int   $lineid           Id of the line to delete
610
     * @return  Object                  Object with cleaned properties
611
     *
612
     * @url     DELETE {id}/lines/{lineid}
613
     *
614
     * @throws RestException 400
615
     * @throws RestException 401
616
     * @throws RestException 404
617
     * @throws RestException 405
618
     */
619
    public function deleteLine($id, $lineid)
620
    {
621
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
622
            throw new RestException(403);
623
        }
624
        if (empty($lineid)) {
625
            throw new RestException(400, 'Line ID is mandatory');
626
        }
627
628
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
629
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
630
        }
631
632
        $result = $this->invoice->fetch($id);
633
        if (!$result) {
634
            throw new RestException(404, 'Invoice not found');
635
        }
636
637
        $updateRes = $this->invoice->deleteLine($lineid, $id);
638
        if ($updateRes > 0) {
639
            return $this->get($id);
640
        } else {
641
            throw new RestException(405, $this->invoice->error);
642
        }
643
    }
644
645
    /**
646
     * Update invoice
647
     *
648
     * @param   int             $id             Id of invoice to update
649
     * @param   array           $request_data   Datas
650
     * @return  Object|false                    Object with cleaned properties
651
     */
652
    public function put($id, $request_data = null)
653
    {
654
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
655
            throw new RestException(403);
656
        }
657
658
        $result = $this->invoice->fetch($id);
659
        if (!$result) {
660
            throw new RestException(404, 'Invoice not found');
661
        }
662
663
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
664
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
665
        }
666
667
        foreach ($request_data as $field => $value) {
668
            if ($field == 'id') {
669
                continue;
670
            }
671
            if ($field === 'caller') {
672
                // 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
673
                $this->invoice->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
674
                continue;
675
            }
676
            if ($field == 'array_options' && is_array($value)) {
677
                foreach ($value as $index => $val) {
678
                    $this->invoice->array_options[$index] = $this->_checkValForAPI($field, $val, $this->invoice);
679
                }
680
                continue;
681
            }
682
683
            $this->invoice->$field = $this->_checkValForAPI($field, $value, $this->invoice);
684
685
            // If cond reglement => update date lim reglement
686
            if ($field == 'cond_reglement_id') {
687
                $this->invoice->date_lim_reglement = $this->invoice->calculate_date_lim_reglement();
688
            }
689
        }
690
691
        // update bank account
692
        if (!empty($this->invoice->fk_account)) {
693
            if ($this->invoice->setBankAccount($this->invoice->fk_account) == 0) {
694
                throw new RestException(400, $this->invoice->error);
695
            }
696
        }
697
698
        if ($this->invoice->update(DolibarrApiAccess::$user)) {
699
            return $this->get($id);
700
        }
701
702
        return false;
703
    }
704
705
    /**
706
     * Delete invoice
707
     *
708
     * @param   int     $id     Invoice ID
709
     * @return  array
710
     */
711
    public function delete($id)
712
    {
713
        if (!DolibarrApiAccess::$user->hasRight('facture', 'supprimer')) {
714
            throw new RestException(403);
715
        }
716
        $result = $this->invoice->fetch($id);
717
        if (!$result) {
718
            throw new RestException(404, 'Invoice not found');
719
        }
720
721
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
722
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
723
        }
724
725
        $result = $this->invoice->delete(DolibarrApiAccess::$user);
726
        if ($result < 0) {
727
            throw new RestException(500, 'Error when deleting invoice');
728
        } elseif ($result == 0) {
729
            throw new RestException(403, 'Invoice not erasable');
730
        }
731
732
        return array(
733
            'success' => array(
734
                'code' => 200,
735
                'message' => 'Invoice deleted'
736
            )
737
        );
738
    }
739
740
    /**
741
     * Add a line to a given invoice
742
     *
743
     * Example of POST query :
744
     * {
745
     *     "desc": "Desc", "subprice": "1.00000000", "qty": "1", "tva_tx": "20.000", "localtax1_tx": "0.000", "localtax2_tx": "0.000",
746
     *     "fk_product": "1", "remise_percent": "0", "date_start": "", "date_end": "", "fk_code_ventilation": 0,  "info_bits": "0",
747
     *     "fk_remise_except": null,  "product_type": "1", "rang": "-1", "special_code": "0", "fk_parent_line": null, "fk_fournprice": null,
748
     *     "pa_ht": "0.00000000", "label": "", "array_options": [], "situation_percent": "100", "fk_prev_id": null, "fk_unit": null
749
     * }
750
     *
751
     * @param int   $id             Id of invoice
752
     * @param array $request_data   InvoiceLine data
753
     *
754
     * @url     POST {id}/lines
755
     *
756
     * @return int
757
     *
758
     * @throws RestException 304
759
     * @throws RestException 401
760
     * @throws RestException 404
761
     * @throws RestException 400
762
     */
763
    public function postLine($id, $request_data = null)
764
    {
765
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
766
            throw new RestException(403);
767
        }
768
769
        $result = $this->invoice->fetch($id);
770
        if (!$result) {
771
            throw new RestException(404, 'Invoice not found');
772
        }
773
774
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
775
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
776
        }
777
778
        $request_data = (object) $request_data;
779
780
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
781
        $request_data->label = sanitizeVal($request_data->label);
782
783
        // Reset fk_parent_line for no child products and special product
784
        if (($request_data->product_type != 9 && empty($request_data->fk_parent_line)) || $request_data->product_type == 9) {
785
            $request_data->fk_parent_line = 0;
786
        }
787
788
        // calculate pa_ht
789
        $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);
790
        $pa_ht = $marginInfos[0];
791
792
        $updateRes = $this->invoice->addline(
793
            $request_data->desc,
794
            $request_data->subprice,
795
            $request_data->qty,
796
            $request_data->tva_tx,
797
            $request_data->localtax1_tx,
798
            $request_data->localtax2_tx,
799
            $request_data->fk_product,
800
            $request_data->remise_percent,
801
            $request_data->date_start,
802
            $request_data->date_end,
803
            $request_data->fk_code_ventilation,
804
            $request_data->info_bits,
805
            $request_data->fk_remise_except,
806
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
807
            $request_data->subprice,
808
            $request_data->product_type,
809
            $request_data->rang,
810
            $request_data->special_code,
811
            $request_data->origin,
812
            $request_data->origin_id,
813
            $request_data->fk_parent_line,
814
            empty($request_data->fk_fournprice) ? null : $request_data->fk_fournprice,
815
            $pa_ht,
816
            $request_data->label,
817
            $request_data->array_options,
818
            $request_data->situation_percent,
819
            $request_data->fk_prev_id,
820
            $request_data->fk_unit,
821
            0,
822
            $request_data->ref_ext
823
        );
824
825
        if ($updateRes < 0) {
826
            throw new RestException(400, 'Unable to insert the new line. Check your inputs. ' . $this->invoice->error);
827
        }
828
829
        return $updateRes;
830
    }
831
832
    /**
833
     * Adds a contact to an invoice
834
     *
835
     * @param   int     $id                 Order ID
836
     * @param   int     $fk_socpeople           Id of thirdparty contact (if source = 'external') or id of user (if source = 'internal') to link
837
     * @param   string  $type_contact           Type of contact (code). Must a code found into table llx_c_type_contact. For example: BILLING
838
     * @param   string  $source                 external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
839
     * @param   int     $notrigger              Disable all triggers
840
     *
841
     * @url POST    {id}/contacts
842
     *
843
     * @return  object
844
     *
845
     * @throws RestException 304
846
     * @throws RestException 401
847
     * @throws RestException 404
848
     * @throws RestException 500 System error
849
     *
850
     */
851
    public function addContact($id, $fk_socpeople, $type_contact, $source, $notrigger = 0)
852
    {
853
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
854
            throw new RestException(403);
855
        }
856
        $result = $this->invoice->fetch($id);
857
        if (!$result) {
858
            throw new RestException(404, 'Invoice not found');
859
        }
860
861
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
862
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
863
        }
864
865
        $result = $this->invoice->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
866
        if ($result < 0) {
867
            throw new RestException(500, 'Error : ' . $this->invoice->error);
868
        }
869
870
        $result = $this->invoice->fetch($id);
871
        if (!$result) {
872
            throw new RestException(404, 'Invoice not found');
873
        }
874
875
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
876
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
877
        }
878
879
        return $this->_cleanObjectDatas($this->invoice);
880
    }
881
882
883
884
    /**
885
     * Sets an invoice as draft
886
     *
887
     * @param   int $id             Order ID
888
     * @param   int $idwarehouse    Warehouse ID
889
     * @return  Object              Object with cleaned properties
890
     *
891
     * @url POST    {id}/settodraft
892
     *
893
     * @throws RestException 304
894
     * @throws RestException 401
895
     * @throws RestException 404
896
     * @throws RestException 500 System error
897
     *
898
     */
899
    public function settodraft($id, $idwarehouse = -1)
900
    {
901
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
902
            throw new RestException(403);
903
        }
904
        $result = $this->invoice->fetch($id);
905
        if (!$result) {
906
            throw new RestException(404, 'Invoice not found');
907
        }
908
909
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
910
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
911
        }
912
913
        $result = $this->invoice->setDraft(DolibarrApiAccess::$user, $idwarehouse);
914
        if ($result == 0) {
915
            throw new RestException(304, 'Nothing done.');
916
        }
917
        if ($result < 0) {
918
            throw new RestException(500, 'Error : ' . $this->invoice->error);
919
        }
920
921
        $result = $this->invoice->fetch($id);
922
        if (!$result) {
923
            throw new RestException(404, 'Invoice not found');
924
        }
925
926
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
927
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
928
        }
929
930
        return $this->_cleanObjectDatas($this->invoice);
931
    }
932
933
934
    /**
935
     * Validate an invoice
936
     *
937
     * If you get a bad value for param notrigger check that ou provide this in body
938
     * {
939
     *   "idwarehouse": 0,
940
     *   "notrigger": 0
941
     * }
942
     *
943
     * @param   int $id                 Invoice ID
944
     * @param   string $force_number    force ref invoice
945
     * @param   int $idwarehouse        Warehouse ID
946
     * @param   int $notrigger          1=Does not execute triggers, 0= execute triggers
947
     * @return  Object|false            Object with cleaned properties
948
     *
949
     * @url POST    {id}/validate
950
     */
951
    public function validate($id, $force_number = '', $idwarehouse = 0, $notrigger = 0)
952
    {
953
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
954
            throw new RestException(403);
955
        }
956
        $result = $this->invoice->fetch($id);
957
        if (!$result) {
958
            throw new RestException(404, 'Invoice not found');
959
        }
960
961
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
962
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
963
        }
964
965
        $result = $this->invoice->validate(DolibarrApiAccess::$user, $force_number, $idwarehouse, $notrigger);
966
        if ($result == 0) {
967
            throw new RestException(304, 'Error nothing done. May be object is already validated');
968
        }
969
        if ($result < 0) {
970
            throw new RestException(500, 'Error when validating Invoice: ' . $this->invoice->error);
971
        }
972
973
        $result = $this->invoice->fetch($id);
974
        if (!$result) {
975
            throw new RestException(404, 'Invoice not found');
976
        }
977
978
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
979
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
980
        }
981
982
        // copy from order
983
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
984
        $this->invoice->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $this->invoice->ref);
985
986
        return $this->_cleanObjectDatas($this->invoice);
987
    }
988
989
    /**
990
     * Sets an invoice as paid
991
     *
992
     * @param   int     $id            Order ID
993
     * @param   string  $close_code    Code filled if we classify to 'Paid completely' when payment is not complete (for escompte for example)
994
     * @param   string  $close_note    Comment defined if we classify to 'Paid' when payment is not complete (for escompte for example)
995
     * @return  Object                 Object with cleaned properties
996
     *
997
     * @url POST    {id}/settopaid
998
     *
999
     * @throws RestException 304
1000
     * @throws RestException 401
1001
     * @throws RestException 404
1002
     * @throws RestException 500 System error
1003
     */
1004
    public function settopaid($id, $close_code = '', $close_note = '')
1005
    {
1006
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1007
            throw new RestException(403);
1008
        }
1009
        $result = $this->invoice->fetch($id);
1010
        if (!$result) {
1011
            throw new RestException(404, 'Invoice not found');
1012
        }
1013
1014
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1015
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1016
        }
1017
1018
        $result = $this->invoice->setPaid(DolibarrApiAccess::$user, $close_code, $close_note);
1019
        if ($result == 0) {
1020
            throw new RestException(304, 'Error nothing done. May be object is already validated');
1021
        }
1022
        if ($result < 0) {
1023
            throw new RestException(500, 'Error : ' . $this->invoice->error);
1024
        }
1025
1026
1027
        $result = $this->invoice->fetch($id);
1028
        if (!$result) {
1029
            throw new RestException(404, 'Invoice not found');
1030
        }
1031
1032
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1033
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1034
        }
1035
1036
        return $this->_cleanObjectDatas($this->invoice);
1037
    }
1038
1039
1040
    /**
1041
     * Sets an invoice as unpaid
1042
     *
1043
     * @param   int     $id             Order ID
1044
     * @return  Object                  Object with cleaned properties
1045
     *
1046
     * @url POST    {id}/settounpaid
1047
     *
1048
     * @throws RestException 304
1049
     * @throws RestException 401
1050
     * @throws RestException 404
1051
     * @throws RestException 500 System error
1052
     */
1053
    public function settounpaid($id)
1054
    {
1055
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1056
            throw new RestException(403);
1057
        }
1058
        $result = $this->invoice->fetch($id);
1059
        if (!$result) {
1060
            throw new RestException(404, 'Invoice not found');
1061
        }
1062
1063
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1064
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1065
        }
1066
1067
        $result = $this->invoice->setUnpaid(DolibarrApiAccess::$user);
1068
        if ($result == 0) {
1069
            throw new RestException(304, 'Nothing done');
1070
        }
1071
        if ($result < 0) {
1072
            throw new RestException(500, 'Error : ' . $this->invoice->error);
1073
        }
1074
1075
1076
        $result = $this->invoice->fetch($id);
1077
        if (!$result) {
1078
            throw new RestException(404, 'Invoice not found');
1079
        }
1080
1081
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1082
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1083
        }
1084
1085
        return $this->_cleanObjectDatas($this->invoice);
1086
    }
1087
1088
    /**
1089
     * Get discount from invoice
1090
     *
1091
     * @param int   $id             Id of invoice
1092
     * @return  Object              Object with cleaned properties
1093
     *
1094
     * @url GET {id}/discount
1095
     */
1096
    public function getDiscount($id)
1097
    {
1098
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1099
1100
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1101
            throw new RestException(403);
1102
        }
1103
1104
        $result = $this->invoice->fetch($id);
1105
        if (!$result) {
1106
            throw new RestException(404, 'Invoice not found');
1107
        }
1108
1109
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1110
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1111
        }
1112
1113
        $discountcheck = new DiscountAbsolute($this->db);
1114
        $result = $discountcheck->fetch(0, $this->invoice->id);
1115
1116
        if ($result == 0) {
1117
            throw new RestException(404, 'Discount not found');
1118
        }
1119
        if ($result < 0) {
1120
            throw new RestException(500, $discountcheck->error);
1121
        }
1122
1123
        return parent::_cleanObjectDatas($discountcheck);
1124
    }
1125
1126
    /**
1127
     * Create a discount (credit available) for a credit note or a deposit.
1128
     *
1129
     * @param   int     $id             Invoice ID
1130
     * @return  Object                  Object with cleaned properties
1131
     *
1132
     * @url POST    {id}/markAsCreditAvailable
1133
     *
1134
     * @throws RestException 304
1135
     * @throws RestException 401
1136
     * @throws RestException 404
1137
     * @throws RestException 500 System error
1138
     */
1139
    public function markAsCreditAvailable($id)
1140
    {
1141
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1142
1143
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1144
            throw new RestException(403);
1145
        }
1146
1147
        $result = $this->invoice->fetch($id);
1148
        if (!$result) {
1149
            throw new RestException(404, 'Invoice not found');
1150
        }
1151
1152
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1153
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1154
        }
1155
1156
        if ($this->invoice->paye) {
1157
            throw new RestException(500, 'Alreay paid');
1158
        }
1159
1160
        $this->invoice->fetch($id);
1161
        $this->invoice->fetch_thirdparty();
1162
1163
        // Check if there is already a discount (protection to avoid duplicate creation when resubmit post)
1164
        $discountcheck = new DiscountAbsolute($this->db);
1165
        $result = $discountcheck->fetch(0, $this->invoice->id);
1166
1167
        $canconvert = 0;
1168
        if ($this->invoice->type == Facture::TYPE_DEPOSIT && empty($discountcheck->id)) {
1169
            $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)
1170
        }
1171
        if (($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_STANDARD) && $this->invoice->paye == 0 && empty($discountcheck->id)) {
1172
            $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)
1173
        }
1174
        if ($canconvert) {
1175
            $this->db->begin();
1176
1177
            $amount_ht = $amount_tva = $amount_ttc = array();
1178
            $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
1179
1180
            // Loop on each vat rate
1181
            $i = 0;
1182
            foreach ($this->invoice->lines as $line) {
1183
                if ($line->product_type < 9 && $line->total_ht != 0) { // Remove lines with product_type greater than or equal to 9
1184
                    // no need to create discount if amount is null
1185
                    $amount_ht[$line->tva_tx] += $line->total_ht;
1186
                    $amount_tva[$line->tva_tx] += $line->total_tva;
1187
                    $amount_ttc[$line->tva_tx] += $line->total_ttc;
1188
                    $multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht;
1189
                    $multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva;
1190
                    $multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc;
1191
                    $i++;
1192
                }
1193
            }
1194
1195
            // Insert one discount by VAT rate category
1196
            $discount = new DiscountAbsolute($this->db);
1197
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1198
                $discount->description = '(CREDIT_NOTE)';
1199
            } elseif ($this->invoice->type == Facture::TYPE_DEPOSIT) {
1200
                $discount->description = '(DEPOSIT)';
1201
            } elseif ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1202
                $discount->description = '(EXCESS RECEIVED)';
1203
            } else {
1204
                throw new RestException(500, 'Cant convert to reduc an Invoice of this type');
1205
            }
1206
1207
            $discount->fk_soc = $this->invoice->socid;
1208
            $discount->socid = $this->invoice->socid;
1209
            $discount->fk_facture_source = $this->invoice->id;
1210
1211
            $error = 0;
1212
1213
            if ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1214
                // If we're on a standard invoice, we have to get excess received to create a discount in TTC without VAT
1215
1216
                // Total payments
1217
                $sql = 'SELECT SUM(pf.amount) as total_payments';
1218
                $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement_facture as pf, ' . MAIN_DB_PREFIX . 'paiement as p';
1219
                $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as c ON p.fk_paiement = c.id';
1220
                $sql .= ' WHERE pf.fk_facture = ' . ((int) $this->invoice->id);
1221
                $sql .= ' AND pf.fk_paiement = p.rowid';
1222
                $sql .= ' AND p.entity IN (' . getEntity('invoice') . ')';
1223
                $resql = $this->db->query($sql);
1224
                if (!$resql) {
1225
                    dol_print_error($this->db);
1226
                }
1227
1228
                $res = $this->db->fetch_object($resql);
1229
                $total_payments = $res->total_payments;
1230
1231
                // Total credit note and deposit
1232
                $total_creditnote_and_deposit = 0;
1233
                $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1234
                $sql .= " re.description, re.fk_facture_source";
1235
                $sql .= " FROM " . MAIN_DB_PREFIX . "societe_remise_except as re";
1236
                $sql .= " WHERE fk_facture = " . ((int) $this->invoice->id);
1237
                $resql = $this->db->query($sql);
1238
                if (!empty($resql)) {
1239
                    while ($obj = $this->db->fetch_object($resql)) {
1240
                        $total_creditnote_and_deposit += $obj->amount_ttc;
1241
                    }
1242
                } else {
1243
                    dol_print_error($this->db);
1244
                }
1245
1246
                $discount->amount_ht = $discount->amount_ttc = $total_payments + $total_creditnote_and_deposit - $this->invoice->total_ttc;
1247
                $discount->amount_tva = 0;
1248
                $discount->tva_tx = 0;
1249
1250
                $result = $discount->create(DolibarrApiAccess::$user);
1251
                if ($result < 0) {
1252
                    $error++;
1253
                }
1254
            }
1255
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_DEPOSIT) {
1256
                foreach ($amount_ht as $tva_tx => $xxx) {
1257
                    $discount->amount_ht = abs($amount_ht[$tva_tx]);
1258
                    $discount->amount_tva = abs($amount_tva[$tva_tx]);
1259
                    $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
1260
                    $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
1261
                    $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
1262
                    $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
1263
                    $discount->tva_tx = abs($tva_tx);
1264
1265
                    $result = $discount->create(DolibarrApiAccess::$user);
1266
                    if ($result < 0) {
1267
                        $error++;
1268
                        break;
1269
                    }
1270
                }
1271
            }
1272
1273
            if (empty($error)) {
1274
                if ($this->invoice->type != Facture::TYPE_DEPOSIT) {
1275
                    // Set the invoice as paid
1276
                    $result = $this->invoice->setPaid(DolibarrApiAccess::$user);
1277
                    if ($result >= 0) {
1278
                        $this->db->commit();
1279
                    } else {
1280
                        $this->db->rollback();
1281
                        throw new RestException(500, 'Could not set paid');
1282
                    }
1283
                } else {
1284
                    $this->db->commit();
1285
                }
1286
            } else {
1287
                $this->db->rollback();
1288
                throw new RestException(500, 'Discount creation error');
1289
            }
1290
        }
1291
1292
        return $this->_cleanObjectDatas($this->invoice);
1293
    }
1294
1295
    /**
1296
     * Add a discount line into an invoice (as an invoice line) using an existing absolute discount
1297
     *
1298
     * Note that this consume the discount.
1299
     *
1300
     * @param int   $id             Id of invoice
1301
     * @param int   $discountid     Id of discount
1302
     * @return int
1303
     *
1304
     * @url     POST {id}/usediscount/{discountid}
1305
     *
1306
     * @throws RestException 400
1307
     * @throws RestException 401
1308
     * @throws RestException 404
1309
     * @throws RestException 405
1310
     */
1311
    public function useDiscount($id, $discountid)
1312
    {
1313
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1314
            throw new RestException(403);
1315
        }
1316
        if (empty($id)) {
1317
            throw new RestException(400, 'Invoice ID is mandatory');
1318
        }
1319
        if (empty($discountid)) {
1320
            throw new RestException(400, 'Discount ID is mandatory');
1321
        }
1322
1323
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1324
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1325
        }
1326
1327
        $result = $this->invoice->fetch($id);
1328
        if (!$result) {
1329
            throw new RestException(404, 'Invoice not found');
1330
        }
1331
1332
        $result = $this->invoice->insert_discount($discountid);
1333
        if ($result < 0) {
1334
            throw new RestException(405, $this->invoice->error);
1335
        }
1336
1337
        return $result;
1338
    }
1339
1340
    /**
1341
     * Add an available credit note discount to payments of an existing invoice.
1342
     *
1343
     *  Note that this consume the credit note.
1344
     *
1345
     * @param int   $id            Id of invoice
1346
     * @param int   $discountid    Id of a discount coming from a credit note
1347
     * @return  int
1348
     *
1349
     * @url     POST {id}/usecreditnote/{discountid}
1350
     *
1351
     * @throws RestException 400
1352
     * @throws RestException 401
1353
     * @throws RestException 404
1354
     * @throws RestException 405
1355
     */
1356
    public function useCreditNote($id, $discountid)
1357
    {
1358
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1359
1360
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1361
            throw new RestException(403);
1362
        }
1363
        if (empty($id)) {
1364
            throw new RestException(400, 'Invoice ID is mandatory');
1365
        }
1366
        if (empty($discountid)) {
1367
            throw new RestException(400, 'Credit ID is mandatory');
1368
        }
1369
1370
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1371
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1372
        }
1373
        $discount = new DiscountAbsolute($this->db);
1374
        $result = $discount->fetch($discountid);
1375
        if (!$result) {
1376
            throw new RestException(404, 'Credit not found');
1377
        }
1378
1379
        $result = $discount->link_to_invoice(0, $id);
1380
        if ($result < 0) {
1381
            throw new RestException(405, $discount->error);
1382
        }
1383
1384
        return $result;
1385
    }
1386
1387
    /**
1388
     * Get list of payments of a given invoice
1389
     *
1390
     * @param   int   $id             Id of invoice
1391
     * @return  array
1392
     *
1393
     * @url     GET {id}/payments
1394
     *
1395
     * @throws RestException 400
1396
     * @throws RestException 401
1397
     * @throws RestException 404
1398
     * @throws RestException 405
1399
     */
1400
    public function getPayments($id)
1401
    {
1402
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1403
            throw new RestException(403);
1404
        }
1405
        if (empty($id)) {
1406
            throw new RestException(400, 'Invoice ID is mandatory');
1407
        }
1408
1409
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1410
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1411
        }
1412
1413
        $result = $this->invoice->fetch($id);
1414
        if (!$result) {
1415
            throw new RestException(404, 'Invoice not found');
1416
        }
1417
1418
        $result = $this->invoice->getListOfPayments();
1419
        if ($result < 0) {
1420
            throw new RestException(405, $this->invoice->error);
1421
        }
1422
1423
        return $result;
1424
    }
1425
1426
1427
    /**
1428
     * Add payment line to a specific invoice with the remain to pay as amount.
1429
     *
1430
     * @param int     $id                               Id of invoice
1431
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1432
     * @param int     $paymentid          {@from body}  Payment mode Id {@min 1}
1433
     * @param string  $closepaidinvoices  {@from body}  Close paid invoices {@choice yes,no}
1434
     * @param int     $accountid          {@from body}  Account Id {@min 1}
1435
     * @param string  $num_payment        {@from body}  Payment number (optional)
1436
     * @param string  $comment            {@from body}  Note private (optional)
1437
     * @param string  $chqemetteur        {@from body}  Payment issuer (mandatory if paymentcode = 'CHQ')
1438
     * @param string  $chqbank            {@from body}  Issuer bank name (optional)
1439
     *
1440
     * @url     POST {id}/payments
1441
     *
1442
     * @return int  Payment ID
1443
     *
1444
     * @throws RestException 400
1445
     * @throws RestException 401
1446
     * @throws RestException 404
1447
     */
1448
    public function addPayment($id, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '')
1449
    {
1450
        require_once constant('DOL_DOCUMENT_ROOT') . '/compta/paiement/class/paiement.class.php';
1451
1452
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1453
            throw new RestException(403);
1454
        }
1455
        if (empty($id)) {
1456
            throw new RestException(400, 'Invoice ID is mandatory');
1457
        }
1458
1459
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1460
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1461
        }
1462
1463
        if (isModEnabled("bank")) {
1464
            if (empty($accountid)) {
1465
                throw new RestException(400, 'Account ID is mandatory');
1466
            }
1467
        }
1468
1469
        if (empty($paymentid)) {
1470
            throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1471
        }
1472
1473
1474
        $result = $this->invoice->fetch($id);
1475
        if (!$result) {
1476
            throw new RestException(404, 'Invoice not found');
1477
        }
1478
1479
        // Calculate amount to pay
1480
        $totalpaid = $this->invoice->getSommePaiement();
1481
        $totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
1482
        $totaldeposits = $this->invoice->getSumDepositsUsed();
1483
        $resteapayer = price2num($this->invoice->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1484
1485
        $this->db->begin();
1486
1487
        $amounts = array();
1488
        $multicurrency_amounts = array();
1489
1490
        // Clean parameters amount if payment is for a credit note
1491
        if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1492
            $resteapayer = price2num($resteapayer, 'MT');
1493
            $amounts[$id] = (float) price2num(-1 * (float) $resteapayer, 'MT');
1494
            // Multicurrency
1495
            $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1496
            $multicurrency_amounts[$id] = (float) price2num(-1 * (float) $newvalue, 'MT');
1497
        } else {
1498
            $resteapayer = price2num($resteapayer, 'MT');
1499
            $amounts[$id] = (float) $resteapayer;
1500
            // Multicurrency
1501
            $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1502
            $multicurrency_amounts[$id] = (float) $newvalue;
1503
        }
1504
1505
        // Creation of payment line
1506
        $paymentobj = new Paiement($this->db);
1507
        $paymentobj->datepaye     = dol_stringtotime($datepaye);
1508
        $paymentobj->amounts      = $amounts; // Array with all payments dispatching with invoice id
1509
        $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1510
        $paymentobj->paiementid = $paymentid;
1511
        $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1512
        $paymentobj->num_payment = $num_payment;
1513
        $paymentobj->note_private = $comment;
1514
1515
        $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1516
        if ($payment_id < 0) {
1517
            $this->db->rollback();
1518
            throw new RestException(400, 'Payment error : ' . $paymentobj->error);
1519
        }
1520
1521
        if (isModEnabled("bank")) {
1522
            $label = '(CustomerInvoicePayment)';
1523
1524
            if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1525
                throw new RestException(400, 'Emetteur is mandatory when payment code is ' . $paymentobj->paiementcode);
1526
            }
1527
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1528
                $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1529
            }
1530
            $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1531
            if ($result < 0) {
1532
                $this->db->rollback();
1533
                throw new RestException(400, 'Add payment to bank error : ' . $paymentobj->error);
1534
            }
1535
        }
1536
1537
        $this->db->commit();
1538
1539
        return $payment_id;
1540
    }
1541
1542
    /**
1543
     * Add a payment to pay partially or completely one or several invoices.
1544
     * Warning: Take care that all invoices are owned by the same customer.
1545
     * Example of value for parameter arrayofamounts: {"1": {"amount": "99.99", "multicurrency_amount": ""}, "2": {"amount": "", "multicurrency_amount": "10"}}
1546
     *
1547
     * @param array   $arrayofamounts     {@from body}  Array with id of invoices with amount to pay for each invoice
1548
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1549
     * @param int     $paymentid           {@from body}  Payment mode Id {@min 1}
1550
     * @param string  $closepaidinvoices   {@from body}  Close paid invoices {@choice yes,no}
1551
     * @param int     $accountid           {@from body}  Account Id {@min 1}
1552
     * @param string  $num_payment         {@from body}  Payment number (optional)
1553
     * @param string  $comment             {@from body}  Note private (optional)
1554
     * @param string  $chqemetteur         {@from body}  Payment issuer (mandatory if paiementcode = 'CHQ')
1555
     * @param string  $chqbank             {@from body}  Issuer bank name (optional)
1556
     * @param string  $ref_ext             {@from body}  External reference (optional)
1557
     * @param bool    $accepthigherpayment {@from body}  Accept higher payments that it remains to be paid (optional)
1558
     *
1559
     * @url     POST /paymentsdistributed
1560
     *
1561
     * @return int  Payment ID
1562
     *
1563
     * @throws RestException 400
1564
     * @throws RestException 401
1565
     * @throws RestException 403
1566
     * @throws RestException 404
1567
     */
1568
    public function addPaymentDistributed($arrayofamounts, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '', $ref_ext = '', $accepthigherpayment = false)
1569
    {
1570
        require_once constant('DOL_DOCUMENT_ROOT') . '/compta/paiement/class/paiement.class.php';
1571
1572
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1573
            throw new RestException(403);
1574
        }
1575
        foreach ($arrayofamounts as $id => $amount) {
1576
            if (empty($id)) {
1577
                throw new RestException(400, 'Invoice ID is mandatory. Fill the invoice id and amount into arrayofamounts parameter. For example: {"1": "99.99", "2": "10"}');
1578
            }
1579
            if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1580
                throw new RestException(403, 'Access not allowed on invoice ID ' . $id . ' for login ' . DolibarrApiAccess::$user->login);
1581
            }
1582
        }
1583
1584
        if (isModEnabled("bank")) {
1585
            if (empty($accountid)) {
1586
                throw new RestException(400, 'Account ID is mandatory');
1587
            }
1588
        }
1589
        if (empty($paymentid)) {
1590
            throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1591
        }
1592
1593
        $this->db->begin();
1594
1595
        $amounts = array();
1596
        $multicurrency_amounts = array();
1597
1598
        // Loop on each invoice to pay
1599
        foreach ($arrayofamounts as $id => $amountarray) {
1600
            $result = $this->invoice->fetch($id);
1601
            if (!$result) {
1602
                $this->db->rollback();
1603
                throw new RestException(404, 'Invoice ID ' . $id . ' not found');
1604
            }
1605
1606
            if (($amountarray["amount"] == "remain" || $amountarray["amount"] > 0) && ($amountarray["multicurrency_amount"] == "remain" || $amountarray["multicurrency_amount"] > 0)) {
1607
                $this->db->rollback();
1608
                throw new RestException(400, 'Payment in both currency ' . $id . ' ( amount: ' . $amountarray["amount"] . ', multicurrency_amount: ' . $amountarray["multicurrency_amount"] . ')');
1609
            }
1610
1611
            $is_multicurrency = 0;
1612
            $total_ttc = $this->invoice->total_ttc;
1613
1614
            if ($amountarray["multicurrency_amount"] > 0 || $amountarray["multicurrency_amount"] == "remain") {
1615
                $is_multicurrency = 1;
1616
                $total_ttc = $this->invoice->multicurrency_total_ttc;
1617
            }
1618
1619
            // Calculate amount to pay
1620
            $totalpaid = $this->invoice->getSommePaiement($is_multicurrency);
1621
            $totalcreditnotes = $this->invoice->getSumCreditNotesUsed($is_multicurrency);
1622
            $totaldeposits = $this->invoice->getSumDepositsUsed($is_multicurrency);
1623
            $remainstopay = $amount = price2num($total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1624
1625
            if (!$is_multicurrency && $amountarray["amount"] != 'remain') {
1626
                $amount = price2num($amountarray["amount"], 'MT');
1627
            }
1628
1629
            if ($is_multicurrency && $amountarray["multicurrency_amount"] != 'remain') {
1630
                $amount = price2num($amountarray["multicurrency_amount"], 'MT');
1631
            }
1632
1633
            if ($amount > $remainstopay && !$accepthigherpayment) {
1634
                $this->db->rollback();
1635
                throw new RestException(400, 'Payment amount on invoice ID ' . $id . ' (' . $amount . ') is higher than remain to pay (' . $remainstopay . ')');
1636
            }
1637
1638
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1639
                $amount = price2num(-1 * (float) $amount, 'MT');
1640
            }
1641
1642
            if ($is_multicurrency) {
1643
                $amounts[$id] = null;
1644
                // Multicurrency
1645
                $multicurrency_amounts[$id] = (float) $amount;
1646
            } else {
1647
                $amounts[$id] = (float) $amount;
1648
                // Multicurrency
1649
                $multicurrency_amounts[$id] = null;
1650
            }
1651
        }
1652
1653
        // Creation of payment line
1654
        $paymentobj = new Paiement($this->db);
1655
        $paymentobj->datepaye     = $datepaye;
1656
        $paymentobj->amounts      = $amounts; // Array with all payments dispatching with invoice id
1657
        $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1658
        $paymentobj->paiementid   = $paymentid;
1659
        $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1660
        $paymentobj->num_payment  = $num_payment;
1661
        $paymentobj->note_private = $comment;
1662
        $paymentobj->ref_ext      = $ref_ext;
1663
        $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1664
        if ($payment_id < 0) {
1665
            $this->db->rollback();
1666
            throw new RestException(400, 'Payment error : ' . $paymentobj->error);
1667
        }
1668
        if (isModEnabled("bank")) {
1669
            $label = '(CustomerInvoicePayment)';
1670
            if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1671
                throw new RestException(400, 'Emetteur is mandatory when payment code is ' . $paymentobj->paiementcode);
1672
            }
1673
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1674
                $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1675
            }
1676
            $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1677
            if ($result < 0) {
1678
                $this->db->rollback();
1679
                throw new RestException(400, 'Add payment to bank error : ' . $paymentobj->error);
1680
            }
1681
        }
1682
1683
        $this->db->commit();
1684
1685
        return $payment_id;
1686
    }
1687
1688
    /**
1689
     * Update a payment
1690
     *
1691
     * @param int       $id             Id of payment
1692
     * @param string    $num_payment    Payment number
1693
     *
1694
     * @url     PUT payments/{id}
1695
     *
1696
     * @return array
1697
     *
1698
     * @throws RestException 400 Bad parameters
1699
     * @throws RestException 401 Not allowed
1700
     * @throws RestException 404 Not found
1701
     */
1702
    public function putPayment($id, $num_payment = '')
1703
    {
1704
        require_once constant('DOL_DOCUMENT_ROOT') . '/compta/paiement/class/paiement.class.php';
1705
1706
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1707
            throw new RestException(403);
1708
        }
1709
        if (empty($id)) {
1710
            throw new RestException(400, 'Payment ID is mandatory');
1711
        }
1712
1713
        $paymentobj = new Paiement($this->db);
1714
        $result = $paymentobj->fetch($id);
1715
1716
        if (!$result) {
1717
            throw new RestException(404, 'Payment not found');
1718
        }
1719
1720
        if (!empty($num_payment)) {
1721
            $result = $paymentobj->update_num($num_payment);
1722
            if ($result < 0) {
1723
                throw new RestException(500, 'Error when updating the payment num');
1724
            }
1725
        }
1726
1727
        return [
1728
            'success' => [
1729
                'code' => 200,
1730
                'message' => 'Payment updated'
1731
            ]
1732
        ];
1733
    }
1734
1735
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1736
    /**
1737
     * Clean sensible object datas
1738
     *
1739
     * @param   Object  $object     Object to clean
1740
     * @return  Object              Object with cleaned properties
1741
     */
1742
    protected function _cleanObjectDatas($object)
1743
    {
1744
		// phpcs:enable
1745
        $object = parent::_cleanObjectDatas($object);
1746
1747
        unset($object->note);
1748
        unset($object->address);
1749
        unset($object->barcode_type);
1750
        unset($object->barcode_type_code);
1751
        unset($object->barcode_type_label);
1752
        unset($object->barcode_type_coder);
1753
        unset($object->canvas);
1754
1755
        return $object;
1756
    }
1757
1758
    /**
1759
     * Validate fields before create or update object
1760
     *
1761
     * @param   array|null    $data       Datas to validate
1762
     * @return  array
1763
     *
1764
     * @throws RestException
1765
     */
1766
    private function _validate($data)
1767
    {
1768
        $invoice = array();
1769
        foreach (Invoices::$FIELDS as $field) {
1770
            if (!isset($data[$field])) {
1771
                throw new RestException(400, "$field field missing");
1772
            }
1773
            $invoice[$field] = $data[$field];
1774
        }
1775
        return $invoice;
1776
    }
1777
1778
1779
    /**
1780
     * Get properties of a template invoice object
1781
     *
1782
     * Return an array with invoice information
1783
     *
1784
     * @param   int     $id             ID of template invoice
1785
     * @param   int     $contact_list   0:Return array contains all properties, 1:Return array contains just id, -1: Do not return contacts/adddesses
1786
     * @return  Object                  Object with cleaned properties
1787
     *
1788
     * @url GET    templates/{id}
1789
     *
1790
     * @throws  RestException
1791
     */
1792
    public function getTemplateInvoice($id, $contact_list = 1)
1793
    {
1794
        return $this->_fetchTemplateInvoice($id, '', '', $contact_list);
1795
    }
1796
1797
    /**
1798
     * Get properties of an invoice object
1799
     *
1800
     * Return an array with invoice information
1801
     *
1802
     * @param   int         $id             ID of order
1803
     * @param   string      $ref            Ref of object
1804
     * @param   string      $ref_ext        External reference of object
1805
     * @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
1806
     * @return  Object                      Object with cleaned properties
1807
     *
1808
     * @throws  RestException
1809
     */
1810
    private function _fetchTemplateInvoice($id, $ref = '', $ref_ext = '', $contact_list = 1)
1811
    {
1812
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1813
            throw new RestException(403);
1814
        }
1815
1816
        $result = $this->template_invoice->fetch($id, $ref, $ref_ext);
1817
        if (!$result) {
1818
            throw new RestException(404, 'Template invoice not found');
1819
        }
1820
1821
        if (!DolibarrApi::_checkAccessToResource('facturerec', $this->template_invoice->id)) {
1822
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1823
        }
1824
1825
        // Add external contacts ids
1826
        if ($contact_list > -1) {
1827
            $tmparray = $this->template_invoice->liste_contact(-1, 'external', $contact_list);
1828
            if (is_array($tmparray)) {
1829
                $this->template_invoice->contacts_ids = $tmparray;
1830
            }
1831
        }
1832
1833
        $this->template_invoice->fetchObjectLinked();
1834
        return $this->_cleanTemplateObjectDatas($this->template_invoice);
1835
    }
1836
1837
1838
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1839
    /**
1840
     * Clean sensible object datas
1841
     *
1842
     * @param   Object  $object     Object to clean
1843
     * @return  Object              Object with cleaned properties
1844
     */
1845
    protected function _cleanTemplateObjectDatas($object)
1846
    {
1847
		// phpcs:enable
1848
        $object = parent::_cleanObjectDatas($object);
1849
1850
        unset($object->note);
1851
        unset($object->address);
1852
        unset($object->barcode_type);
1853
        unset($object->barcode_type_code);
1854
        unset($object->barcode_type_label);
1855
        unset($object->barcode_type_coder);
1856
        unset($object->canvas);
1857
1858
        return $object;
1859
    }
1860
}
1861