Passed
Pull Request — main (#3)
by Rafael
54:18
created

Invoices::getTemplateInvoice()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
namespace Dolibarr\Code\ComptaFacture\Api;
25
26
use Dolibarr\Code\Api\Classes\DolibarrApiAccess;
27
use Dolibarr\Code\Commande\Classes\Commande;
28
use Dolibarr\Code\Compta\Classes\Facture;
29
use Dolibarr\Code\Compta\Classes\FactureRec;
30
use Dolibarr\Code\Contrat\Classes\Contrat;
31
use Dolibarr\Code\Core\Classes\DiscountAbsolute;
32
use Dolibarr\Core\Base\DolibarrApi;
33
use Luracast\Restler\RestException;
34
use Paiement;
35
36
/**
37
 * API class for invoices
38
 *
39
 * @access protected
40
 * @class  DolibarrApiAccess {@requires user,external}
41
 */
42
class Invoices extends DolibarrApi
43
{
44
    /**
45
     *
46
     * @var array   $FIELDS     Mandatory fields, checked when create and update object
47
     */
48
    public static $FIELDS = array(
49
        'socid',
50
    );
51
52
    /**
53
     * @var Facture $invoice {@type Facture}
54
     */
55
    private $invoice;
56
57
    /**
58
     * @var FactureRec $templte_invoice {@type FactureRec}
59
     */
60
    private $template_invoice;
61
62
63
    /**
64
     * Constructor
65
     */
66
    public function __construct()
67
    {
68
        global $db;
69
        $this->db = $db;
70
        $this->invoice = new Facture($this->db);
71
        $this->template_invoice = new FactureRec($this->db);
72
    }
73
74
    /**
75
     * Get properties of a invoice object
76
     *
77
     * Return an array with invoice information
78
     *
79
     * @param   int     $id             ID of invoice
80
     * @param   int     $contact_list   0:Return array contains all properties, 1:Return array contains just id, -1: Do not return contacts/adddesses
81
     * @return  array                  Object with cleaned properties
82
     *
83
     * @throws  RestException
84
     */
85
    public function get($id, $contact_list = 1)
86
    {
87
        return $this->_fetch($id, '', '', $contact_list);
88
    }
89
90
    /**
91
     * Get properties of an invoice object by ref
92
     *
93
     * Return an array with invoice information
94
     *
95
     * @param   string      $ref            Ref of object
96
     * @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
97
     * @return  array                      Object with cleaned properties
98
     *
99
     * @url GET    ref/{ref}
100
     *
101
     * @throws  RestException
102
     */
103
    public function getByRef($ref, $contact_list = 1)
104
    {
105
        return $this->_fetch('', $ref, '', $contact_list);
106
    }
107
108
    /**
109
     * Get properties of an invoice object by ref_ext
110
     *
111
     * Return an array with invoice information
112
     *
113
     * @param   string      $ref_ext        External reference of object
114
     * @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
115
     * @return  array                      Object with cleaned properties
116
     *
117
     * @url GET    ref_ext/{ref_ext}
118
     *
119
     * @throws  RestException
120
     */
121
    public function getByRefExt($ref_ext, $contact_list = 1)
122
    {
123
        return $this->_fetch('', '', $ref_ext, $contact_list);
124
    }
125
126
    /**
127
     * Get properties of an invoice object
128
     *
129
     * Return an array with invoice information
130
     *
131
     * @param   int         $id             ID of order
132
     * @param   string      $ref            Ref of object
133
     * @param   string      $ref_ext        External reference of object
134
     * @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
135
     * @return  Object                      Object with cleaned properties
136
     *
137
     * @throws  RestException
138
     */
139
    private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = 1)
140
    {
141
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
142
            throw new RestException(403);
143
        }
144
145
        $result = $this->invoice->fetch($id, $ref, $ref_ext);
146
        if (!$result) {
147
            throw new RestException(404, 'Invoice not found');
148
        }
149
150
        // Get payment details
151
        $this->invoice->totalpaid = $this->invoice->getSommePaiement();
152
        $this->invoice->totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
153
        $this->invoice->totaldeposits = $this->invoice->getSumDepositsUsed();
154
        $this->invoice->remaintopay = price2num($this->invoice->total_ttc - $this->invoice->totalpaid - $this->invoice->totalcreditnotes - $this->invoice->totaldeposits, 'MT');
155
156
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
157
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
158
        }
159
160
        // Add external contacts ids
161
        if ($contact_list > -1) {
162
            $tmparray = $this->invoice->liste_contact(-1, 'external', $contact_list);
163
            if (is_array($tmparray)) {
164
                $this->invoice->contacts_ids = $tmparray;
165
            }
166
        }
167
168
        $this->invoice->fetchObjectLinked();
169
170
        // Add online_payment_url, copied from order
171
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
172
        $this->invoice->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $this->invoice->ref);
173
174
        return $this->_cleanObjectDatas($this->invoice);
175
    }
176
177
    /**
178
     * List invoices
179
     *
180
     * Get a list of invoices
181
     *
182
     * @param string    $sortfield        Sort field
183
     * @param string    $sortorder        Sort order
184
     * @param int       $limit            Limit for list
185
     * @param int       $page             Page number
186
     * @param string    $thirdparty_ids   Thirdparty ids to filter orders of (example '1' or '1,2,3') {@pattern /^[0-9,]*$/i}
187
     * @param string    $status           Filter by invoice status : draft | unpaid | paid | cancelled
188
     * @param string    $sqlfilters       Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
189
     * @param string    $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names
190
     * @return array                      Array of invoice objects
191
     *
192
     * @throws RestException 404 Not found
193
     * @throws RestException 503 Error
194
     */
195
    public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $status = '', $sqlfilters = '', $properties = '')
196
    {
197
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
198
            throw new RestException(403);
199
        }
200
201
        $obj_ret = array();
202
203
        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
204
        $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
205
206
        // If the internal user must only see his customers, force searching by him
207
        $search_sale = 0;
208
        if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
209
            $search_sale = DolibarrApiAccess::$user->id;
210
        }
211
212
        $sql = "SELECT t.rowid";
213
        $sql .= " FROM " . MAIN_DB_PREFIX . "facture AS t";
214
        $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
215
        $sql .= ' WHERE t.entity IN (' . getEntity('invoice') . ')';
216
        if ($socids) {
217
            $sql .= " AND t.fk_soc IN (" . $this->db->sanitize($socids) . ")";
218
        }
219
        // Search on sale representative
220
        if ($search_sale && $search_sale != '-1') {
221
            if ($search_sale == -2) {
222
                $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
223
            } elseif ($search_sale > 0) {
224
                $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) . ")";
225
            }
226
        }
227
        // Filter by status
228
        if ($status == 'draft') {
229
            $sql .= " AND t.fk_statut IN (0)";
230
        }
231
        if ($status == 'unpaid') {
232
            $sql .= " AND t.fk_statut IN (1)";
233
        }
234
        if ($status == 'paid') {
235
            $sql .= " AND t.fk_statut IN (2)";
236
        }
237
        if ($status == 'cancelled') {
238
            $sql .= " AND t.fk_statut IN (3)";
239
        }
240
        // Add sql filters
241
        if ($sqlfilters) {
242
            $errormessage = '';
243
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
244
            if ($errormessage) {
245
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
246
            }
247
        }
248
249
        $sql .= $this->db->order($sortfield, $sortorder);
250
        if ($limit) {
251
            if ($page < 0) {
252
                $page = 0;
253
            }
254
            $offset = $limit * $page;
255
256
            $sql .= $this->db->plimit($limit + 1, $offset);
257
        }
258
259
        $result = $this->db->query($sql);
260
        if ($result) {
261
            $i = 0;
262
            $num = $this->db->num_rows($result);
263
            $min = min($num, ($limit <= 0 ? $num : $limit));
264
            while ($i < $min) {
265
                $obj = $this->db->fetch_object($result);
266
                $invoice_static = new Facture($this->db);
267
                if ($invoice_static->fetch($obj->rowid)) {
268
                    // Get payment details
269
                    $invoice_static->totalpaid = $invoice_static->getSommePaiement();
270
                    $invoice_static->totalcreditnotes = $invoice_static->getSumCreditNotesUsed();
271
                    $invoice_static->totaldeposits = $invoice_static->getSumDepositsUsed();
272
                    $invoice_static->remaintopay = price2num($invoice_static->total_ttc - $invoice_static->totalpaid - $invoice_static->totalcreditnotes - $invoice_static->totaldeposits, 'MT');
273
274
                    // Add external contacts ids
275
                    $tmparray = $invoice_static->liste_contact(-1, 'external', 1);
276
                    if (is_array($tmparray)) {
277
                        $invoice_static->contacts_ids = $tmparray;
278
                    }
279
                    // Add online_payment_url, copied from order
280
                    require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
281
                    $invoice_static->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $invoice_static->ref);
282
283
                    $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($invoice_static), $properties);
284
                }
285
                $i++;
286
            }
287
        } else {
288
            throw new RestException(503, 'Error when retrieve invoice list : ' . $this->db->lasterror());
289
        }
290
291
        return $obj_ret;
292
    }
293
294
    /**
295
     * Create invoice object
296
     *
297
     * @param array $request_data   Request datas
298
     * @return int                  ID of invoice
299
     */
300
    public function post($request_data = null)
301
    {
302
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
303
            throw new RestException(403, "Insuffisant rights");
304
        }
305
        // Check mandatory fields
306
        $result = $this->_validate($request_data);
307
308
        foreach ($request_data as $field => $value) {
309
            if ($field === 'caller') {
310
                // 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
311
                $this->invoice->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
312
                continue;
313
            }
314
315
            $this->invoice->$field = $this->_checkValForAPI($field, $value, $this->invoice);
316
        }
317
        if (!array_key_exists('date', $request_data)) {
318
            $this->invoice->date = dol_now();
319
        }
320
        /* We keep lines as an array
321
         if (isset($request_data["lines"])) {
322
            $lines = array();
323
            foreach ($request_data["lines"] as $line) {
324
                array_push($lines, (object) $line);
325
            }
326
            $this->invoice->lines = $lines;
327
        }*/
328
329
        if ($this->invoice->create(DolibarrApiAccess::$user, 0, (empty($request_data["date_lim_reglement"]) ? 0 : $request_data["date_lim_reglement"])) < 0) {
330
            throw new RestException(500, "Error creating invoice", array_merge(array($this->invoice->error), $this->invoice->errors));
331
        }
332
        return ((int) $this->invoice->id);
333
    }
334
335
    /**
336
     * Create an invoice using an existing order.
337
     *
338
     * @param int   $orderid       Id of the order
339
     * @return  array              Object with cleaned properties
340
     *
341
     * @url     POST /createfromorder/{orderid}
342
     *
343
     * @throws RestException 400
344
     * @throws RestException 401
345
     * @throws RestException 404
346
     * @throws RestException 405
347
     */
348
    public function createInvoiceFromOrder($orderid)
349
    {
350
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
351
            throw new RestException(403);
352
        }
353
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
354
            throw new RestException(403);
355
        }
356
        if (empty($orderid)) {
357
            throw new RestException(400, 'Order ID is mandatory');
358
        }
359
360
        $order = new Commande($this->db);
361
        $result = $order->fetch($orderid);
362
        if (!$result) {
363
            throw new RestException(404, 'Order not found');
364
        }
365
366
        $result = $this->invoice->createFromOrder($order, DolibarrApiAccess::$user);
367
        if ($result < 0) {
368
            throw new RestException(405, $this->invoice->error);
369
        }
370
        $this->invoice->fetchObjectLinked();
371
        return $this->_cleanObjectDatas($this->invoice);
372
    }
373
374
    /**
375
    * Create an invoice using a contract.
376
    *
377
    * @param int   $contractid       Id of the contract
378
     * @return     array                          Object with cleaned properties
379
    *
380
    * @url     POST /createfromcontract/{contractid}
381
    *
382
    * @throws RestException 400
383
    * @throws RestException 401
384
    * @throws RestException 404
385
    * @throws RestException 405
386
    */
387
    public function createInvoiceFromContract($contractid)
388
    {
389
    
390
        if (!DolibarrApiAccess::$user->hasRight('contrat', 'lire')) {
391
            throw new RestException(403);
392
        }
393
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
394
            throw new RestException(403);
395
        }
396
        if (empty($contractid)) {
397
            throw new RestException(400, 'Contract ID is mandatory');
398
        }
399
400
        $contract = new Contrat($this->db);
401
        $result = $contract->fetch($contractid);
402
        if (!$result) {
403
            throw new RestException(404, 'Contract not found');
404
        }
405
406
        $result = $this->invoice->createFromContract($contract, DolibarrApiAccess::$user);
407
        if ($result < 0) {
408
            throw new RestException(405, $this->invoice->error);
409
        }
410
        $this->invoice->fetchObjectLinked();
411
        return $this->_cleanObjectDatas($this->invoice);
412
    }
413
414
    /**
415
     * Get lines of an invoice
416
     *
417
     * @param   int   $id               Id of invoice
418
     * @return  array                   Array of lines
419
     *
420
     * @url GET {id}/lines
421
     */
422
    public function getLines($id)
423
    {
424
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
425
            throw new RestException(403);
426
        }
427
428
        $result = $this->invoice->fetch($id);
429
        if (!$result) {
430
            throw new RestException(404, 'Invoice not found');
431
        }
432
433
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
434
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
435
        }
436
        $this->invoice->getLinesArray();
437
        $result = array();
438
        foreach ($this->invoice->lines as $line) {
439
            array_push($result, $this->_cleanObjectDatas($line));
440
        }
441
        return $result;
442
    }
443
444
    /**
445
     * Update a line to a given invoice
446
     *
447
     * @param   int   $id             Id of invoice to update
448
     * @param   int   $lineid         Id of line to update
449
     * @param   array $request_data   InvoiceLine data
450
     * @return  array                Object with cleaned properties
451
     *
452
     * @url PUT {id}/lines/{lineid}
453
     *
454
     * @throws RestException 304
455
     * @throws RestException 401
456
     * @throws RestException 404 Invoice not found
457
     */
458
    public function putLine($id, $lineid, $request_data = null)
459
    {
460
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
461
            throw new RestException(403);
462
        }
463
464
        $result = $this->invoice->fetch($id);
465
        if (!$result) {
466
            throw new RestException(404, 'Invoice not found');
467
        }
468
469
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
470
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
471
        }
472
473
        $request_data = (object) $request_data;
474
475
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
476
        $request_data->label = sanitizeVal($request_data->label);
477
478
        $updateRes = $this->invoice->updateline(
479
            $lineid,
480
            $request_data->desc,
481
            $request_data->subprice,
482
            $request_data->qty,
483
            $request_data->remise_percent,
484
            $request_data->date_start,
485
            $request_data->date_end,
486
            $request_data->tva_tx,
487
            $request_data->localtax1_tx,
488
            $request_data->localtax2_tx,
489
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
490
            $request_data->info_bits,
491
            $request_data->product_type,
492
            $request_data->fk_parent_line,
493
            0,
494
            $request_data->fk_fournprice,
495
            $request_data->pa_ht,
496
            $request_data->label,
497
            $request_data->special_code,
498
            $request_data->array_options,
499
            $request_data->situation_percent,
500
            $request_data->fk_unit,
501
            $request_data->multicurrency_subprice,
502
            0,
503
            $request_data->ref_ext,
504
            $request_data->rang
505
        );
506
507
        if ($updateRes > 0) {
508
            $result = $this->get($id);
509
            unset($result->line);
510
            return $this->_cleanObjectDatas($result);
511
        } else {
512
            throw new RestException(304, $this->invoice->error);
513
        }
514
    }
515
516
    /**
517
     * Add a contact type of given invoice
518
     *
519
     * @param   int    $id             Id of invoice to update
520
     * @param   int    $contactid      Id of contact to add
521
     * @param   string $type           Type of the contact (BILLING, SHIPPING, CUSTOMER)
522
     * @return  array
523
     *
524
     * @url POST {id}/contact/{contactid}/{type}
525
     *
526
     * @throws RestException 401
527
     * @throws RestException 404
528
     */
529
    public function postContact($id, $contactid, $type)
530
    {
531
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
532
            throw new RestException(403);
533
        }
534
535
        $result = $this->invoice->fetch($id);
536
537
        if (!$result) {
538
            throw new RestException(404, 'Invoice not found');
539
        }
540
541
        if (!in_array($type, array('BILLING', 'SHIPPING', 'CUSTOMER'), true)) {
542
            throw new RestException(500, 'Availables types: BILLING, SHIPPING OR CUSTOMER');
543
        }
544
545
        if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
546
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
547
        }
548
549
        $result = $this->invoice->add_contact($contactid, $type, 'external');
550
551
        if (!$result) {
552
            throw new RestException(500, 'Error when added the contact');
553
        }
554
555
        return array(
556
            'success' => array(
557
                'code' => 200,
558
                'message' => 'Contact linked to the invoice'
559
            )
560
        );
561
    }
562
563
    /**
564
     * Delete a contact type of given invoice
565
     *
566
     * @param   int    $id             Id of invoice to update
567
     * @param   int    $contactid      Row key of the contact in the array contact_ids.
568
     * @param   string $type           Type of the contact (BILLING, SHIPPING, CUSTOMER).
569
     * @return  array                 Object with cleaned properties
570
     *
571
     * @url DELETE {id}/contact/{contactid}/{type}
572
     *
573
     * @throws RestException 401
574
     * @throws RestException 404
575
     * @throws RestException 500 System error
576
     */
577
    public function deleteContact($id, $contactid, $type)
578
    {
579
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
580
            throw new RestException(403);
581
        }
582
583
        $result = $this->invoice->fetch($id);
584
585
        if (!$result) {
586
            throw new RestException(404, 'Invoice not found');
587
        }
588
589
        if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
590
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
591
        }
592
593
        $contacts = $this->invoice->liste_contact();
594
595
        foreach ($contacts as $contact) {
0 ignored issues
show
Bug introduced by
The expression $contacts of type integer is not traversable.
Loading history...
596
            if ($contact['id'] == $contactid && $contact['code'] == $type) {
597
                $result = $this->invoice->delete_contact($contact['rowid']);
598
599
                if (!$result) {
600
                    throw new RestException(500, 'Error when deleted the contact');
601
                }
602
            }
603
        }
604
605
        return $this->_cleanObjectDatas($this->invoice);
606
    }
607
608
    /**
609
     * Deletes a line of a given invoice
610
     *
611
     * @param   int   $id               Id of invoice
612
     * @param   int   $lineid           Id of the line to delete
613
     * @return  array                  Object with cleaned properties
614
     *
615
     * @url     DELETE {id}/lines/{lineid}
616
     *
617
     * @throws RestException 400
618
     * @throws RestException 401
619
     * @throws RestException 404
620
     * @throws RestException 405
621
     */
622
    public function deleteLine($id, $lineid)
623
    {
624
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
625
            throw new RestException(403);
626
        }
627
        if (empty($lineid)) {
628
            throw new RestException(400, 'Line ID is mandatory');
629
        }
630
631
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
632
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
633
        }
634
635
        $result = $this->invoice->fetch($id);
636
        if (!$result) {
637
            throw new RestException(404, 'Invoice not found');
638
        }
639
640
        $updateRes = $this->invoice->deleteLine($lineid, $id);
641
        if ($updateRes > 0) {
642
            return $this->get($id);
643
        } else {
644
            throw new RestException(405, $this->invoice->error);
645
        }
646
    }
647
648
    /**
649
     * Update invoice
650
     *
651
     * @param   int             $id             Id of invoice to update
652
     * @param   array           $request_data   Datas
653
     * @return  Object|false                    Object with cleaned properties
654
     */
655
    public function put($id, $request_data = null)
656
    {
657
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
658
            throw new RestException(403);
659
        }
660
661
        $result = $this->invoice->fetch($id);
662
        if (!$result) {
663
            throw new RestException(404, 'Invoice not found');
664
        }
665
666
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
667
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
668
        }
669
670
        foreach ($request_data as $field => $value) {
671
            if ($field == 'id') {
672
                continue;
673
            }
674
            if ($field === 'caller') {
675
                // 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
676
                $this->invoice->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
677
                continue;
678
            }
679
            if ($field == 'array_options' && is_array($value)) {
680
                foreach ($value as $index => $val) {
681
                    $this->invoice->array_options[$index] = $this->_checkValForAPI($field, $val, $this->invoice);
682
                }
683
                continue;
684
            }
685
686
            $this->invoice->$field = $this->_checkValForAPI($field, $value, $this->invoice);
687
688
            // If cond reglement => update date lim reglement
689
            if ($field == 'cond_reglement_id') {
690
                $this->invoice->date_lim_reglement = $this->invoice->calculate_date_lim_reglement();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->invoice->calculate_date_lim_reglement() can also be of type string. However, the property $date_lim_reglement is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
691
            }
692
        }
693
694
        // update bank account
695
        if (!empty($this->invoice->fk_account)) {
696
            if ($this->invoice->setBankAccount($this->invoice->fk_account) == 0) {
697
                throw new RestException(400, $this->invoice->error);
698
            }
699
        }
700
701
        if ($this->invoice->update(DolibarrApiAccess::$user)) {
702
            return $this->get($id);
703
        }
704
705
        return false;
706
    }
707
708
    /**
709
     * Delete invoice
710
     *
711
     * @param   int     $id     Invoice ID
712
     * @return  array
713
     */
714
    public function delete($id)
715
    {
716
        if (!DolibarrApiAccess::$user->hasRight('facture', 'supprimer')) {
717
            throw new RestException(403);
718
        }
719
        $result = $this->invoice->fetch($id);
720
        if (!$result) {
721
            throw new RestException(404, 'Invoice not found');
722
        }
723
724
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
725
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
726
        }
727
728
        $result = $this->invoice->delete(DolibarrApiAccess::$user);
729
        if ($result < 0) {
730
            throw new RestException(500, 'Error when deleting invoice');
731
        } elseif ($result == 0) {
732
            throw new RestException(403, 'Invoice not erasable');
733
        }
734
735
        return array(
736
            'success' => array(
737
                'code' => 200,
738
                'message' => 'Invoice deleted'
739
            )
740
        );
741
    }
742
743
    /**
744
     * Add a line to a given invoice
745
     *
746
     * Example of POST query :
747
     * {
748
     *     "desc": "Desc", "subprice": "1.00000000", "qty": "1", "tva_tx": "20.000", "localtax1_tx": "0.000", "localtax2_tx": "0.000",
749
     *     "fk_product": "1", "remise_percent": "0", "date_start": "", "date_end": "", "fk_code_ventilation": 0,  "info_bits": "0",
750
     *     "fk_remise_except": null,  "product_type": "1", "rang": "-1", "special_code": "0", "fk_parent_line": null, "fk_fournprice": null,
751
     *     "pa_ht": "0.00000000", "label": "", "array_options": [], "situation_percent": "100", "fk_prev_id": null, "fk_unit": null
752
     * }
753
     *
754
     * @param int   $id             Id of invoice
755
     * @param array $request_data   InvoiceLine data
756
     *
757
     * @url     POST {id}/lines
758
     *
759
     * @return int
760
     *
761
     * @throws RestException 304
762
     * @throws RestException 401
763
     * @throws RestException 404
764
     * @throws RestException 400
765
     */
766
    public function postLine($id, $request_data = null)
767
    {
768
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
769
            throw new RestException(403);
770
        }
771
772
        $result = $this->invoice->fetch($id);
773
        if (!$result) {
774
            throw new RestException(404, 'Invoice not found');
775
        }
776
777
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
778
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
779
        }
780
781
        $request_data = (object) $request_data;
782
783
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
784
        $request_data->label = sanitizeVal($request_data->label);
785
786
        // Reset fk_parent_line for no child products and special product
787
        if (($request_data->product_type != 9 && empty($request_data->fk_parent_line)) || $request_data->product_type == 9) {
788
            $request_data->fk_parent_line = 0;
789
        }
790
791
        // calculate pa_ht
792
        $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);
793
        $pa_ht = $marginInfos[0];
794
795
        $updateRes = $this->invoice->addline(
796
            $request_data->desc,
797
            $request_data->subprice,
798
            $request_data->qty,
799
            $request_data->tva_tx,
800
            $request_data->localtax1_tx,
801
            $request_data->localtax2_tx,
802
            $request_data->fk_product,
803
            $request_data->remise_percent,
804
            $request_data->date_start,
805
            $request_data->date_end,
806
            $request_data->fk_code_ventilation,
807
            $request_data->info_bits,
808
            $request_data->fk_remise_except,
809
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
810
            $request_data->subprice,
811
            $request_data->product_type,
812
            $request_data->rang,
813
            $request_data->special_code,
814
            $request_data->origin,
815
            $request_data->origin_id,
816
            $request_data->fk_parent_line,
817
            empty($request_data->fk_fournprice) ? null : $request_data->fk_fournprice,
818
            $pa_ht,
819
            $request_data->label,
820
            $request_data->array_options,
821
            $request_data->situation_percent,
822
            $request_data->fk_prev_id,
823
            $request_data->fk_unit,
824
            0,
825
            $request_data->ref_ext
826
        );
827
828
        if ($updateRes < 0) {
829
            throw new RestException(400, 'Unable to insert the new line. Check your inputs. ' . $this->invoice->error);
830
        }
831
832
        return $updateRes;
833
    }
834
835
    /**
836
     * Adds a contact to an invoice
837
     *
838
     * @param   int     $id                 Order ID
839
     * @param   int     $fk_socpeople           Id of thirdparty contact (if source = 'external') or id of user (if source = 'internal') to link
840
     * @param   string  $type_contact           Type of contact (code). Must a code found into table llx_c_type_contact. For example: BILLING
841
     * @param   string  $source                 external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
842
     * @param   int     $notrigger              Disable all triggers
843
     *
844
     * @url POST    {id}/contacts
845
     *
846
     * @return  object
847
     *
848
     * @throws RestException 304
849
     * @throws RestException 401
850
     * @throws RestException 404
851
     * @throws RestException 500 System error
852
     *
853
     */
854
    public function addContact($id, $fk_socpeople, $type_contact, $source, $notrigger = 0)
855
    {
856
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
857
            throw new RestException(403);
858
        }
859
        $result = $this->invoice->fetch($id);
860
        if (!$result) {
861
            throw new RestException(404, 'Invoice not found');
862
        }
863
864
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
865
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
866
        }
867
868
        $result = $this->invoice->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
869
        if ($result < 0) {
870
            throw new RestException(500, 'Error : ' . $this->invoice->error);
871
        }
872
873
        $result = $this->invoice->fetch($id);
874
        if (!$result) {
875
            throw new RestException(404, 'Invoice not found');
876
        }
877
878
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
879
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
880
        }
881
882
        return $this->_cleanObjectDatas($this->invoice);
883
    }
884
885
886
887
    /**
888
     * Sets an invoice as draft
889
     *
890
     * @param   int $id             Order ID
891
     * @param   int $idwarehouse    Warehouse ID
892
     * @return  array              Object with cleaned properties
893
     *
894
     * @url POST    {id}/settodraft
895
     *
896
     * @throws RestException 304
897
     * @throws RestException 401
898
     * @throws RestException 404
899
     * @throws RestException 500 System error
900
     *
901
     */
902
    public function settodraft($id, $idwarehouse = -1)
903
    {
904
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
905
            throw new RestException(403);
906
        }
907
        $result = $this->invoice->fetch($id);
908
        if (!$result) {
909
            throw new RestException(404, 'Invoice not found');
910
        }
911
912
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
913
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
914
        }
915
916
        $result = $this->invoice->setDraft(DolibarrApiAccess::$user, $idwarehouse);
917
        if ($result == 0) {
918
            throw new RestException(304, 'Nothing done.');
919
        }
920
        if ($result < 0) {
921
            throw new RestException(500, 'Error : ' . $this->invoice->error);
922
        }
923
924
        $result = $this->invoice->fetch($id);
925
        if (!$result) {
926
            throw new RestException(404, 'Invoice not found');
927
        }
928
929
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
930
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
931
        }
932
933
        return $this->_cleanObjectDatas($this->invoice);
934
    }
935
936
937
    /**
938
     * Validate an invoice
939
     *
940
     * If you get a bad value for param notrigger check that ou provide this in body
941
     * {
942
     *   "idwarehouse": 0,
943
     *   "notrigger": 0
944
     * }
945
     *
946
     * @param   int $id                 Invoice ID
947
     * @param   string $force_number    force ref invoice
948
     * @param   int $idwarehouse        Warehouse ID
949
     * @param   int $notrigger          1=Does not execute triggers, 0= execute triggers
950
     * @return  Object|false            Object with cleaned properties
951
     *
952
     * @url POST    {id}/validate
953
     */
954
    public function validate($id, $force_number = '', $idwarehouse = 0, $notrigger = 0)
955
    {
956
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
957
            throw new RestException(403);
958
        }
959
        $result = $this->invoice->fetch($id);
960
        if (!$result) {
961
            throw new RestException(404, 'Invoice not found');
962
        }
963
964
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
965
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
966
        }
967
968
        $result = $this->invoice->validate(DolibarrApiAccess::$user, $force_number, $idwarehouse, $notrigger);
969
        if ($result == 0) {
970
            throw new RestException(304, 'Error nothing done. May be object is already validated');
971
        }
972
        if ($result < 0) {
973
            throw new RestException(500, 'Error when validating Invoice: ' . $this->invoice->error);
974
        }
975
976
        $result = $this->invoice->fetch($id);
977
        if (!$result) {
978
            throw new RestException(404, 'Invoice not found');
979
        }
980
981
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
982
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
983
        }
984
985
        // copy from order
986
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
987
        $this->invoice->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $this->invoice->ref);
988
989
        return $this->_cleanObjectDatas($this->invoice);
990
    }
991
992
    /**
993
     * Sets an invoice as paid
994
     *
995
     * @param   int     $id            Order ID
996
     * @param   string  $close_code    Code filled if we classify to 'Paid completely' when payment is not complete (for escompte for example)
997
     * @param   string  $close_note    Comment defined if we classify to 'Paid' when payment is not complete (for escompte for example)
998
     * @return  array                 Object with cleaned properties
999
     *
1000
     * @url POST    {id}/settopaid
1001
     *
1002
     * @throws RestException 304
1003
     * @throws RestException 401
1004
     * @throws RestException 404
1005
     * @throws RestException 500 System error
1006
     */
1007
    public function settopaid($id, $close_code = '', $close_note = '')
1008
    {
1009
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1010
            throw new RestException(403);
1011
        }
1012
        $result = $this->invoice->fetch($id);
1013
        if (!$result) {
1014
            throw new RestException(404, 'Invoice not found');
1015
        }
1016
1017
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1018
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1019
        }
1020
1021
        $result = $this->invoice->setPaid(DolibarrApiAccess::$user, $close_code, $close_note);
1022
        if ($result == 0) {
1023
            throw new RestException(304, 'Error nothing done. May be object is already validated');
1024
        }
1025
        if ($result < 0) {
1026
            throw new RestException(500, 'Error : ' . $this->invoice->error);
1027
        }
1028
1029
1030
        $result = $this->invoice->fetch($id);
1031
        if (!$result) {
1032
            throw new RestException(404, 'Invoice not found');
1033
        }
1034
1035
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1036
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1037
        }
1038
1039
        return $this->_cleanObjectDatas($this->invoice);
1040
    }
1041
1042
1043
    /**
1044
     * Sets an invoice as unpaid
1045
     *
1046
     * @param   int     $id             Order ID
1047
     * @return  array                  Object with cleaned properties
1048
     *
1049
     * @url POST    {id}/settounpaid
1050
     *
1051
     * @throws RestException 304
1052
     * @throws RestException 401
1053
     * @throws RestException 404
1054
     * @throws RestException 500 System error
1055
     */
1056
    public function settounpaid($id)
1057
    {
1058
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1059
            throw new RestException(403);
1060
        }
1061
        $result = $this->invoice->fetch($id);
1062
        if (!$result) {
1063
            throw new RestException(404, 'Invoice not found');
1064
        }
1065
1066
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1067
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1068
        }
1069
1070
        $result = $this->invoice->setUnpaid(DolibarrApiAccess::$user);
1071
        if ($result == 0) {
1072
            throw new RestException(304, 'Nothing done');
1073
        }
1074
        if ($result < 0) {
1075
            throw new RestException(500, 'Error : ' . $this->invoice->error);
1076
        }
1077
1078
1079
        $result = $this->invoice->fetch($id);
1080
        if (!$result) {
1081
            throw new RestException(404, 'Invoice not found');
1082
        }
1083
1084
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1085
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1086
        }
1087
1088
        return $this->_cleanObjectDatas($this->invoice);
1089
    }
1090
1091
    /**
1092
     * Get discount from invoice
1093
     *
1094
     * @param int   $id             Id of invoice
1095
     * @return  array              Object with cleaned properties
1096
     *
1097
     * @url GET {id}/discount
1098
     */
1099
    public function getDiscount($id)
1100
    {
1101
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1102
1103
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1104
            throw new RestException(403);
1105
        }
1106
1107
        $result = $this->invoice->fetch($id);
1108
        if (!$result) {
1109
            throw new RestException(404, 'Invoice not found');
1110
        }
1111
1112
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1113
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1114
        }
1115
1116
        $discountcheck = new DiscountAbsolute($this->db);
1117
        $result = $discountcheck->fetch(0, $this->invoice->id);
1118
1119
        if ($result == 0) {
1120
            throw new RestException(404, 'Discount not found');
1121
        }
1122
        if ($result < 0) {
1123
            throw new RestException(500, $discountcheck->error);
1124
        }
1125
1126
        return parent::_cleanObjectDatas($discountcheck);
1127
    }
1128
1129
    /**
1130
     * Create a discount (credit available) for a credit note or a deposit.
1131
     *
1132
     * @param   int     $id             Invoice ID
1133
     * @return  array                  Object with cleaned properties
1134
     *
1135
     * @url POST    {id}/markAsCreditAvailable
1136
     *
1137
     * @throws RestException 304
1138
     * @throws RestException 401
1139
     * @throws RestException 404
1140
     * @throws RestException 500 System error
1141
     */
1142
    public function markAsCreditAvailable($id)
1143
    {
1144
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1145
1146
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1147
            throw new RestException(403);
1148
        }
1149
1150
        $result = $this->invoice->fetch($id);
1151
        if (!$result) {
1152
            throw new RestException(404, 'Invoice not found');
1153
        }
1154
1155
        if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1156
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1157
        }
1158
1159
        if ($this->invoice->paye) {
1160
            throw new RestException(500, 'Alreay paid');
1161
        }
1162
1163
        $this->invoice->fetch($id);
1164
        $this->invoice->fetch_thirdparty();
1165
1166
        // Check if there is already a discount (protection to avoid duplicate creation when resubmit post)
1167
        $discountcheck = new DiscountAbsolute($this->db);
1168
        $result = $discountcheck->fetch(0, $this->invoice->id);
1169
1170
        $canconvert = 0;
1171
        if ($this->invoice->type == Facture::TYPE_DEPOSIT && empty($discountcheck->id)) {
1172
            $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)
1173
        }
1174
        if (($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_STANDARD) && $this->invoice->paye == 0 && empty($discountcheck->id)) {
1175
            $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)
1176
        }
1177
        if ($canconvert) {
1178
            $this->db->begin();
1179
1180
            $amount_ht = $amount_tva = $amount_ttc = array();
1181
            $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
1182
1183
            // Loop on each vat rate
1184
            $i = 0;
1185
            foreach ($this->invoice->lines as $line) {
1186
                if ($line->product_type < 9 && $line->total_ht != 0) { // Remove lines with product_type greater than or equal to 9
1187
                    // no need to create discount if amount is null
1188
                    $amount_ht[$line->tva_tx] += $line->total_ht;
1189
                    $amount_tva[$line->tva_tx] += $line->total_tva;
1190
                    $amount_ttc[$line->tva_tx] += $line->total_ttc;
1191
                    $multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht;
1192
                    $multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva;
1193
                    $multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc;
1194
                    $i++;
1195
                }
1196
            }
1197
1198
            // Insert one discount by VAT rate category
1199
            $discount = new DiscountAbsolute($this->db);
1200
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1201
                $discount->description = '(CREDIT_NOTE)';
1202
            } elseif ($this->invoice->type == Facture::TYPE_DEPOSIT) {
1203
                $discount->description = '(DEPOSIT)';
1204
            } elseif ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1205
                $discount->description = '(EXCESS RECEIVED)';
1206
            } else {
1207
                throw new RestException(500, 'Cant convert to reduc an Invoice of this type');
1208
            }
1209
1210
            $discount->fk_soc = $this->invoice->socid;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Core\Class...scountAbsolute::$fk_soc has been deprecated: Use socid instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1210
            /** @scrutinizer ignore-deprecated */ $discount->fk_soc = $this->invoice->socid;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1211
            $discount->socid = $this->invoice->socid;
1212
            $discount->fk_facture_source = $this->invoice->id;
1213
1214
            $error = 0;
1215
1216
            if ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1217
                // If we're on a standard invoice, we have to get excess received to create a discount in TTC without VAT
1218
1219
                // Total payments
1220
                $sql = 'SELECT SUM(pf.amount) as total_payments';
1221
                $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement_facture as pf, ' . MAIN_DB_PREFIX . 'paiement as p';
1222
                $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as c ON p.fk_paiement = c.id';
1223
                $sql .= ' WHERE pf.fk_facture = ' . ((int) $this->invoice->id);
1224
                $sql .= ' AND pf.fk_paiement = p.rowid';
1225
                $sql .= ' AND p.entity IN (' . getEntity('invoice') . ')';
1226
                $resql = $this->db->query($sql);
1227
                if (!$resql) {
1228
                    dol_print_error($this->db);
1229
                }
1230
1231
                $res = $this->db->fetch_object($resql);
1232
                $total_payments = $res->total_payments;
1233
1234
                // Total credit note and deposit
1235
                $total_creditnote_and_deposit = 0;
1236
                $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1237
                $sql .= " re.description, re.fk_facture_source";
1238
                $sql .= " FROM " . MAIN_DB_PREFIX . "societe_remise_except as re";
1239
                $sql .= " WHERE fk_facture = " . ((int) $this->invoice->id);
1240
                $resql = $this->db->query($sql);
1241
                if (!empty($resql)) {
1242
                    while ($obj = $this->db->fetch_object($resql)) {
1243
                        $total_creditnote_and_deposit += $obj->amount_ttc;
1244
                    }
1245
                } else {
1246
                    dol_print_error($this->db);
1247
                }
1248
1249
                $discount->amount_ht = $discount->amount_ttc = $total_payments + $total_creditnote_and_deposit - $this->invoice->total_ttc;
1250
                $discount->amount_tva = 0;
1251
                $discount->tva_tx = 0;
1252
1253
                $result = $discount->create(DolibarrApiAccess::$user);
1254
                if ($result < 0) {
1255
                    $error++;
1256
                }
1257
            }
1258
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_DEPOSIT) {
1259
                foreach ($amount_ht as $tva_tx => $xxx) {
1260
                    $discount->amount_ht = abs($amount_ht[$tva_tx]);
1261
                    $discount->amount_tva = abs($amount_tva[$tva_tx]);
1262
                    $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
1263
                    $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
1264
                    $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
1265
                    $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
1266
                    $discount->tva_tx = abs($tva_tx);
1267
1268
                    $result = $discount->create(DolibarrApiAccess::$user);
1269
                    if ($result < 0) {
1270
                        $error++;
1271
                        break;
1272
                    }
1273
                }
1274
            }
1275
1276
            if (empty($error)) {
1277
                if ($this->invoice->type != Facture::TYPE_DEPOSIT) {
1278
                    // Set the invoice as paid
1279
                    $result = $this->invoice->setPaid(DolibarrApiAccess::$user);
1280
                    if ($result >= 0) {
1281
                        $this->db->commit();
1282
                    } else {
1283
                        $this->db->rollback();
1284
                        throw new RestException(500, 'Could not set paid');
1285
                    }
1286
                } else {
1287
                    $this->db->commit();
1288
                }
1289
            } else {
1290
                $this->db->rollback();
1291
                throw new RestException(500, 'Discount creation error');
1292
            }
1293
        }
1294
1295
        return $this->_cleanObjectDatas($this->invoice);
1296
    }
1297
1298
    /**
1299
     * Add a discount line into an invoice (as an invoice line) using an existing absolute discount
1300
     *
1301
     * Note that this consume the discount.
1302
     *
1303
     * @param int   $id             Id of invoice
1304
     * @param int   $discountid     Id of discount
1305
     * @return int
1306
     *
1307
     * @url     POST {id}/usediscount/{discountid}
1308
     *
1309
     * @throws RestException 400
1310
     * @throws RestException 401
1311
     * @throws RestException 404
1312
     * @throws RestException 405
1313
     */
1314
    public function useDiscount($id, $discountid)
1315
    {
1316
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1317
            throw new RestException(403);
1318
        }
1319
        if (empty($id)) {
1320
            throw new RestException(400, 'Invoice ID is mandatory');
1321
        }
1322
        if (empty($discountid)) {
1323
            throw new RestException(400, 'Discount ID is mandatory');
1324
        }
1325
1326
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1327
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1328
        }
1329
1330
        $result = $this->invoice->fetch($id);
1331
        if (!$result) {
1332
            throw new RestException(404, 'Invoice not found');
1333
        }
1334
1335
        $result = $this->invoice->insert_discount($discountid);
1336
        if ($result < 0) {
1337
            throw new RestException(405, $this->invoice->error);
1338
        }
1339
1340
        return $result;
1341
    }
1342
1343
    /**
1344
     * Add an available credit note discount to payments of an existing invoice.
1345
     *
1346
     *  Note that this consume the credit note.
1347
     *
1348
     * @param int   $id            Id of invoice
1349
     * @param int   $discountid    Id of a discount coming from a credit note
1350
     * @return  int
1351
     *
1352
     * @url     POST {id}/usecreditnote/{discountid}
1353
     *
1354
     * @throws RestException 400
1355
     * @throws RestException 401
1356
     * @throws RestException 404
1357
     * @throws RestException 405
1358
     */
1359
    public function useCreditNote($id, $discountid)
1360
    {
1361
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php';
1362
1363
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1364
            throw new RestException(403);
1365
        }
1366
        if (empty($id)) {
1367
            throw new RestException(400, 'Invoice ID is mandatory');
1368
        }
1369
        if (empty($discountid)) {
1370
            throw new RestException(400, 'Credit ID is mandatory');
1371
        }
1372
1373
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1374
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1375
        }
1376
        $discount = new DiscountAbsolute($this->db);
1377
        $result = $discount->fetch($discountid);
1378
        if (!$result) {
1379
            throw new RestException(404, 'Credit not found');
1380
        }
1381
1382
        $result = $discount->link_to_invoice(0, $id);
1383
        if ($result < 0) {
1384
            throw new RestException(405, $discount->error);
1385
        }
1386
1387
        return $result;
1388
    }
1389
1390
    /**
1391
     * Get list of payments of a given invoice
1392
     *
1393
     * @param   int   $id             Id of invoice
1394
     * @return  array
1395
     *
1396
     * @url     GET {id}/payments
1397
     *
1398
     * @throws RestException 400
1399
     * @throws RestException 401
1400
     * @throws RestException 404
1401
     * @throws RestException 405
1402
     */
1403
    public function getPayments($id)
1404
    {
1405
        if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1406
            throw new RestException(403);
1407
        }
1408
        if (empty($id)) {
1409
            throw new RestException(400, 'Invoice ID is mandatory');
1410
        }
1411
1412
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1413
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1414
        }
1415
1416
        $result = $this->invoice->fetch($id);
1417
        if (!$result) {
1418
            throw new RestException(404, 'Invoice not found');
1419
        }
1420
1421
        $result = $this->invoice->getListOfPayments();
1422
        if ($result < 0) {
1423
            throw new RestException(405, $this->invoice->error);
1424
        }
1425
1426
        return $result;
1427
    }
1428
1429
1430
    /**
1431
     * Add payment line to a specific invoice with the remain to pay as amount.
1432
     *
1433
     * @param int     $id                               Id of invoice
1434
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1435
     * @param int     $paymentid          {@from body}  Payment mode Id {@min 1}
1436
     * @param string  $closepaidinvoices  {@from body}  Close paid invoices {@choice yes,no}
1437
     * @param int     $accountid          {@from body}  Account Id {@min 1}
1438
     * @param string  $num_payment        {@from body}  Payment number (optional)
1439
     * @param string  $comment            {@from body}  Note private (optional)
1440
     * @param string  $chqemetteur        {@from body}  Payment issuer (mandatory if paymentcode = 'CHQ')
1441
     * @param string  $chqbank            {@from body}  Issuer bank name (optional)
1442
     *
1443
     * @url     POST {id}/payments
1444
     *
1445
     * @return int  Payment ID
1446
     *
1447
     * @throws RestException 400
1448
     * @throws RestException 401
1449
     * @throws RestException 404
1450
     */
1451
    public function addPayment($id, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '')
1452
    {
1453
1454
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1455
            throw new RestException(403);
1456
        }
1457
        if (empty($id)) {
1458
            throw new RestException(400, 'Invoice ID is mandatory');
1459
        }
1460
1461
        if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1462
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1463
        }
1464
1465
        if (isModEnabled("bank")) {
1466
            if (empty($accountid)) {
1467
                throw new RestException(400, 'Account ID is mandatory');
1468
            }
1469
        }
1470
1471
        if (empty($paymentid)) {
1472
            throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1473
        }
1474
1475
1476
        $result = $this->invoice->fetch($id);
1477
        if (!$result) {
1478
            throw new RestException(404, 'Invoice not found');
1479
        }
1480
1481
        // Calculate amount to pay
1482
        $totalpaid = $this->invoice->getSommePaiement();
1483
        $totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
1484
        $totaldeposits = $this->invoice->getSumDepositsUsed();
1485
        $resteapayer = price2num($this->invoice->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1486
1487
        $this->db->begin();
1488
1489
        $amounts = array();
1490
        $multicurrency_amounts = array();
1491
1492
        // Clean parameters amount if payment is for a credit note
1493
        if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1494
            $resteapayer = price2num($resteapayer, 'MT');
1495
            $amounts[$id] = (float) price2num(-1 * (float) $resteapayer, 'MT');
1496
            // Multicurrency
1497
            $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1498
            $multicurrency_amounts[$id] = (float) price2num(-1 * (float) $newvalue, 'MT');
1499
        } else {
1500
            $resteapayer = price2num($resteapayer, 'MT');
1501
            $amounts[$id] = (float) $resteapayer;
1502
            // Multicurrency
1503
            $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1504
            $multicurrency_amounts[$id] = (float) $newvalue;
1505
        }
1506
1507
        // Creation of payment line
1508
        $paymentobj = new Paiement($this->db);
1509
        $paymentobj->datepaye     = dol_stringtotime($datepaye);
1510
        $paymentobj->amounts      = $amounts; // Array with all payments dispatching with invoice id
1511
        $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1512
        $paymentobj->paiementid = $paymentid;
1513
        $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1514
        $paymentobj->num_payment = $num_payment;
1515
        $paymentobj->note_private = $comment;
1516
1517
        $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1518
        if ($payment_id < 0) {
1519
            $this->db->rollback();
1520
            throw new RestException(400, 'Payment error : ' . $paymentobj->error);
1521
        }
1522
1523
        if (isModEnabled("bank")) {
1524
            $label = '(CustomerInvoicePayment)';
1525
1526
            if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1527
                throw new RestException(400, 'Emetteur is mandatory when payment code is ' . $paymentobj->paiementcode);
1528
            }
1529
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1530
                $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1531
            }
1532
            $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1533
            if ($result < 0) {
1534
                $this->db->rollback();
1535
                throw new RestException(400, 'Add payment to bank error : ' . $paymentobj->error);
1536
            }
1537
        }
1538
1539
        $this->db->commit();
1540
1541
        return $payment_id;
1542
    }
1543
1544
    /**
1545
     * Add a payment to pay partially or completely one or several invoices.
1546
     * Warning: Take care that all invoices are owned by the same customer.
1547
     * Example of value for parameter arrayofamounts: {"1": {"amount": "99.99", "multicurrency_amount": ""}, "2": {"amount": "", "multicurrency_amount": "10"}}
1548
     *
1549
     * @param array   $arrayofamounts     {@from body}  Array with id of invoices with amount to pay for each invoice
1550
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1551
     * @param int     $paymentid           {@from body}  Payment mode Id {@min 1}
1552
     * @param string  $closepaidinvoices   {@from body}  Close paid invoices {@choice yes,no}
1553
     * @param int     $accountid           {@from body}  Account Id {@min 1}
1554
     * @param string  $num_payment         {@from body}  Payment number (optional)
1555
     * @param string  $comment             {@from body}  Note private (optional)
1556
     * @param string  $chqemetteur         {@from body}  Payment issuer (mandatory if paiementcode = 'CHQ')
1557
     * @param string  $chqbank             {@from body}  Issuer bank name (optional)
1558
     * @param string  $ref_ext             {@from body}  External reference (optional)
1559
     * @param bool    $accepthigherpayment {@from body}  Accept higher payments that it remains to be paid (optional)
1560
     *
1561
     * @url     POST /paymentsdistributed
1562
     *
1563
     * @return int  Payment ID
1564
     *
1565
     * @throws RestException 400
1566
     * @throws RestException 401
1567
     * @throws RestException 403
1568
     * @throws RestException 404
1569
     */
1570
    public function addPaymentDistributed($arrayofamounts, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '', $ref_ext = '', $accepthigherpayment = false)
1571
    {
1572
1573
        if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1574
            throw new RestException(403);
1575
        }
1576
        foreach ($arrayofamounts as $id => $amount) {
1577
            if (empty($id)) {
1578
                throw new RestException(400, 'Invoice ID is mandatory. Fill the invoice id and amount into arrayofamounts parameter. For example: {"1": "99.99", "2": "10"}');
1579
            }
1580
            if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1581
                throw new RestException(403, 'Access not allowed on invoice ID ' . $id . ' for login ' . DolibarrApiAccess::$user->login);
1582
            }
1583
        }
1584
1585
        if (isModEnabled("bank")) {
1586
            if (empty($accountid)) {
1587
                throw new RestException(400, 'Account ID is mandatory');
1588
            }
1589
        }
1590
        if (empty($paymentid)) {
1591
            throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1592
        }
1593
1594
        $this->db->begin();
1595
1596
        $amounts = array();
1597
        $multicurrency_amounts = array();
1598
1599
        // Loop on each invoice to pay
1600
        foreach ($arrayofamounts as $id => $amountarray) {
1601
            $result = $this->invoice->fetch($id);
1602
            if (!$result) {
1603
                $this->db->rollback();
1604
                throw new RestException(404, 'Invoice ID ' . $id . ' not found');
1605
            }
1606
1607
            if (($amountarray["amount"] == "remain" || $amountarray["amount"] > 0) && ($amountarray["multicurrency_amount"] == "remain" || $amountarray["multicurrency_amount"] > 0)) {
1608
                $this->db->rollback();
1609
                throw new RestException(400, 'Payment in both currency ' . $id . ' ( amount: ' . $amountarray["amount"] . ', multicurrency_amount: ' . $amountarray["multicurrency_amount"] . ')');
1610
            }
1611
1612
            $is_multicurrency = 0;
1613
            $total_ttc = $this->invoice->total_ttc;
1614
1615
            if ($amountarray["multicurrency_amount"] > 0 || $amountarray["multicurrency_amount"] == "remain") {
1616
                $is_multicurrency = 1;
1617
                $total_ttc = $this->invoice->multicurrency_total_ttc;
1618
            }
1619
1620
            // Calculate amount to pay
1621
            $totalpaid = $this->invoice->getSommePaiement($is_multicurrency);
1622
            $totalcreditnotes = $this->invoice->getSumCreditNotesUsed($is_multicurrency);
1623
            $totaldeposits = $this->invoice->getSumDepositsUsed($is_multicurrency);
1624
            $remainstopay = $amount = price2num($total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1625
1626
            if (!$is_multicurrency && $amountarray["amount"] != 'remain') {
1627
                $amount = price2num($amountarray["amount"], 'MT');
1628
            }
1629
1630
            if ($is_multicurrency && $amountarray["multicurrency_amount"] != 'remain') {
1631
                $amount = price2num($amountarray["multicurrency_amount"], 'MT');
1632
            }
1633
1634
            if ($amount > $remainstopay && !$accepthigherpayment) {
1635
                $this->db->rollback();
1636
                throw new RestException(400, 'Payment amount on invoice ID ' . $id . ' (' . $amount . ') is higher than remain to pay (' . $remainstopay . ')');
1637
            }
1638
1639
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1640
                $amount = price2num(-1 * (float) $amount, 'MT');
1641
            }
1642
1643
            if ($is_multicurrency) {
1644
                $amounts[$id] = null;
1645
                // Multicurrency
1646
                $multicurrency_amounts[$id] = (float) $amount;
1647
            } else {
1648
                $amounts[$id] = (float) $amount;
1649
                // Multicurrency
1650
                $multicurrency_amounts[$id] = null;
1651
            }
1652
        }
1653
1654
        // Creation of payment line
1655
        $paymentobj = new Paiement($this->db);
1656
        $paymentobj->datepaye     = $datepaye;
1657
        $paymentobj->amounts      = $amounts; // Array with all payments dispatching with invoice id
1658
        $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1659
        $paymentobj->paiementid   = $paymentid;
1660
        $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1661
        $paymentobj->num_payment  = $num_payment;
1662
        $paymentobj->note_private = $comment;
1663
        $paymentobj->ref_ext      = $ref_ext;
1664
        $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1665
        if ($payment_id < 0) {
1666
            $this->db->rollback();
1667
            throw new RestException(400, 'Payment error : ' . $paymentobj->error);
1668
        }
1669
        if (isModEnabled("bank")) {
1670
            $label = '(CustomerInvoicePayment)';
1671
            if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1672
                throw new RestException(400, 'Emetteur is mandatory when payment code is ' . $paymentobj->paiementcode);
1673
            }
1674
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1675
                $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1676
            }
1677
            $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1678
            if ($result < 0) {
1679
                $this->db->rollback();
1680
                throw new RestException(400, 'Add payment to bank error : ' . $paymentobj->error);
1681
            }
1682
        }
1683
1684
        $this->db->commit();
1685
1686
        return $payment_id;
1687
    }
1688
1689
    /**
1690
     * Update a payment
1691
     *
1692
     * @param int       $id             Id of payment
1693
     * @param string    $num_payment    Payment number
1694
     *
1695
     * @url     PUT payments/{id}
1696
     *
1697
     * @return array
1698
     *
1699
     * @throws RestException 400 Bad parameters
1700
     * @throws RestException 401 Not allowed
1701
     * @throws RestException 404 Not found
1702
     */
1703
    public function putPayment($id, $num_payment = '')
1704
    {
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  array                  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  array                      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