Completed
Branch develop (f83f74)
by
unknown
26:35
created

Invoices::markAsCreditAvailable()   D

Complexity

Conditions 15
Paths 46

Size

Total Lines 97

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
nc 46
nop 1
dl 0
loc 97
rs 4.7987
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
/* Copyright (C) 2015   Jean-François Ferry     <[email protected]>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
use Luracast\Restler\RestException;
19
20
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
21
22
/**
23
 * API class for invoices
24
 *
25
 * @access protected
26
 * @class  DolibarrApiAccess {@requires user,external}
27
 */
28
class Invoices extends DolibarrApi
29
{
30
    /**
31
     *
32
     * @var array   $FIELDS     Mandatory fields, checked when create and update object
33
     */
34
    static $FIELDS = array(
35
        'socid',
36
    );
37
38
    /**
39
     * @var Facture $invoice {@type Facture}
40
     */
41
    public $invoice;
42
43
    /**
44
     * Constructor
45
     */
46
    function __construct()
47
    {
48
		global $db, $conf;
49
		$this->db = $db;
50
        $this->invoice = new Facture($this->db);
51
    }
52
53
    /**
54
     * Get properties of a invoice object
55
     *
56
     * Return an array with invoice informations
57
     *
58
     * @param 	int 	$id           ID of invoice
59
     * @param   int     $contact_list 0:Return array contains all properties, 1:Return array contains just id
60
     * @return 	array|mixed data without useless information
61
     *
62
     * @throws 	RestException
63
     */
64
	function get($id, $contact_list = 1)
65
	{
66
		if(! DolibarrApiAccess::$user->rights->facture->lire) {
67
			throw new RestException(401);
68
		}
69
70
		$result = $this->invoice->fetch($id);
71
		if (! $result) {
72
			throw new RestException(404, 'Invoice not found');
73
		}
74
75
		// Get payment details
76
		$this->invoice->totalpaye = $this->invoice->getSommePaiement();
77
		$this->invoice->totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
78
		$this->invoice->totaldeposits = $this->invoice->getSumDepositsUsed();
79
		$this->invoice->resteapayer = price2num($this->invoice->total_ttc - $this->invoice->totalpaye - $this->invoice->totalcreditnotes - $this->invoice->totaldeposits, 'MT');
80
81
		if (! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
82
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
83
		}
84
85
		// Add external contacts ids
86
		$this->invoice->contacts_ids = $this->invoice->liste_contact(-1, 'external', $contact_list);
87
88
		$this->invoice->fetchObjectLinked();
89
		return $this->_cleanObjectDatas($this->invoice);
90
	}
91
92
    /**
93
     * List invoices
94
     *
95
     * Get a list of invoices
96
     *
97
     * @param string	$sortfield	      Sort field
98
     * @param string	$sortorder	      Sort order
99
     * @param int		$limit		      Limit for list
100
     * @param int		$page		      Page number
101
     * @param string   	$thirdparty_ids	  Thirdparty ids to filter orders of. {@example '1' or '1,2,3'} {@pattern /^[0-9,]*$/i}
102
     * @param string	$status		      Filter by invoice status : draft | unpaid | paid | cancelled
103
     * @param string    $sqlfilters       Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
104
     * @return array                      Array of invoice objects
105
     *
106
	 * @throws RestException
107
     */
108
    function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $status = '', $sqlfilters = '')
109
    {
110
        global $db, $conf;
111
112
        $obj_ret = array();
113
114
        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
115
        $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
116
117
        // If the internal user must only see his customers, force searching by him
118
        $search_sale = 0;
119
        if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
120
121
        $sql = "SELECT t.rowid";
122
        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
123
        $sql.= " FROM ".MAIN_DB_PREFIX."facture as t";
124
125
        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
126
127
        $sql.= ' WHERE t.entity IN ('.getEntity('invoice').')';
128
        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= " AND t.fk_soc = sc.fk_soc";
129
        if ($socids) $sql.= " AND t.fk_soc IN (".$socids.")";
130
131
        if ($search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc";		// Join for the needed table to filter by sale
132
133
		// Filter by status
134
        if ($status == 'draft')     $sql.= " AND t.fk_statut IN (0)";
135
        if ($status == 'unpaid')    $sql.= " AND t.fk_statut IN (1)";
136
        if ($status == 'paid')      $sql.= " AND t.fk_statut IN (2)";
137
        if ($status == 'cancelled') $sql.= " AND t.fk_statut IN (3)";
138
        // Insert sale filter
139
        if ($search_sale > 0)
140
        {
141
            $sql .= " AND sc.fk_user = ".$search_sale;
142
        }
143
        // Add sql filters
144
        if ($sqlfilters)
145
        {
146
            if (! DolibarrApi::_checkFilters($sqlfilters))
147
            {
148
                throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
149
            }
150
	        $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
151
            $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
152
        }
153
154
        $sql.= $db->order($sortfield, $sortorder);
155
        if ($limit)
156
        {
157
            if ($page < 0)
158
            {
159
                $page = 0;
160
            }
161
            $offset = $limit * $page;
162
163
            $sql.= $db->plimit($limit + 1, $offset);
164
        }
165
166
        $result = $db->query($sql);
167
        if ($result)
168
        {
169
            $i=0;
170
            $num = $db->num_rows($result);
171
            $min = min($num, ($limit <= 0 ? $num : $limit));
172
            while ($i < $min)
173
            {
174
                $obj = $db->fetch_object($result);
175
                $invoice_static = new Facture($db);
176
                if ($invoice_static->fetch($obj->rowid))
177
                {
178
                	// Get payment details
179
                	$invoice_static->totalpaid = $invoice_static->getSommePaiement();
180
                	$invoice_static->totalcreditnotes = $invoice_static->getSumCreditNotesUsed();
181
                	$invoice_static->totaldeposits = $invoice_static->getSumDepositsUsed();
182
                	$invoice_static->remaintopay = price2num($invoice_static->total_ttc - $invoice_static->totalpaid - $invoice_static->totalcreditnotes - $invoice_static->totaldeposits, 'MT');
183
184
					// Add external contacts ids
185
					$invoice_static->contacts_ids = $invoice_static->liste_contact(-1, 'external', 1);
186
187
                	$obj_ret[] = $this->_cleanObjectDatas($invoice_static);
188
                }
189
                $i++;
190
            }
191
        }
192
        else {
193
            throw new RestException(503, 'Error when retrieve invoice list : '.$db->lasterror());
194
        }
195
        if( ! count($obj_ret)) {
196
            throw new RestException(404, 'No invoice found');
197
        }
198
		return $obj_ret;
199
    }
200
201
    /**
202
     * Create invoice object
203
     *
204
     * @param array $request_data   Request datas
205
     * @return int                  ID of invoice
206
     */
207
    function post($request_data = null)
208
    {
209
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
210
			throw new RestException(401, "Insuffisant rights");
211
		}
212
        // Check mandatory fields
213
        $result = $this->_validate($request_data);
214
215
        foreach($request_data as $field => $value) {
216
            $this->invoice->$field = $value;
217
        }
218
        if(! array_key_exists('date', $request_data)) {
219
            $this->invoice->date = dol_now();
220
        }
221
        /* We keep lines as an array
222
         if (isset($request_data["lines"])) {
223
            $lines = array();
224
            foreach ($request_data["lines"] as $line) {
225
                array_push($lines, (object) $line);
226
            }
227
            $this->invoice->lines = $lines;
228
        }*/
229
230
        if ($this->invoice->create(DolibarrApiAccess::$user) < 0) {
231
            throw new RestException(500, "Error creating invoice", array_merge(array($this->invoice->error), $this->invoice->errors));
232
        }
233
        return $this->invoice->id;
234
    }
235
236
     /**
237
     * Create an invoice using an existing order.
238
     *
239
     *
240
     * @param int   $orderid       Id of the order
241
     *
242
     * @url     POST /createfromorder/{orderid}
243
     *
244
     * @return int
245
     * @throws 400
246
     * @throws 401
247
     * @throws 404
248
     * @throws 405
249
     */
250
    function createInvoiceFromOrder($orderid)
251
    {
252
253
        require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
254
255
        if(! DolibarrApiAccess::$user->rights->commande->lire) {
256
            throw new RestException(401);
257
        }
258
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
259
            throw new RestException(401);
260
        }
261
        if(empty($orderid)) {
262
            throw new RestException(400, 'Order ID is mandatory');
263
        }
264
265
        $order = new Commande($this->db);
266
        $result = $order->fetch($orderid);
267
        if( ! $result ) {
268
            throw new RestException(404, 'Order not found');
269
        }
270
271
        $result = $this->invoice->createFromOrder($order, DolibarrApiAccess::$user);
272
        if( $result < 0) {
273
            throw new RestException(405, $this->invoice->error);
274
        }
275
        $this->invoice->fetchObjectLinked();
276
        return $this->_cleanObjectDatas($this->invoice);
277
    }
278
279
    /**
280
     * Get lines of an invoice
281
     *
282
     * @param int   $id             Id of invoice
283
     *
284
     * @url	GET {id}/lines
285
     *
286
     * @return int
287
     */
288
    function getLines($id)
289
    {
290
    	if(! DolibarrApiAccess::$user->rights->facture->lire) {
291
    		throw new RestException(401);
292
    	}
293
294
    	$result = $this->invoice->fetch($id);
295
    	if( ! $result ) {
296
    		throw new RestException(404, 'Invoice not found');
297
    	}
298
299
    	if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
300
    		throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
301
    	}
302
    	$this->invoice->getLinesArray();
303
    	$result = array();
304
    	foreach ($this->invoice->lines as $line) {
305
    		array_push($result, $this->_cleanObjectDatas($line));
306
    	}
307
    	return $result;
308
    }
309
310
    /**
311
     * Update a line to a given invoice
312
     *
313
     * @param int   $id             Id of invoice to update
314
     * @param int   $lineid         Id of line to update
315
     * @param array $request_data   InvoiceLine data
316
     *
317
     * @url	PUT {id}/lines/{lineid}
318
     *
319
     * @return object
320
     *
321
     * @throws 200
322
     * @throws 304
323
     * @throws 401
324
     * @throws 404
325
     */
326
    function putLine($id, $lineid, $request_data = null)
327
    {
328
    	if(! DolibarrApiAccess::$user->rights->facture->creer) {
329
    		throw new RestException(401);
330
    	}
331
332
    	$result = $this->invoice->fetch($id);
333
    	if( ! $result ) {
334
    		throw new RestException(404, 'Invoice not found');
335
    	}
336
337
    	if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
338
    		throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
339
    	}
340
    	$request_data = (object) $request_data;
341
        $updateRes = $this->invoice->updateline(
342
    		$lineid,
343
    		$request_data->desc,
344
    		$request_data->subprice,
345
    		$request_data->qty,
346
    		$request_data->remise_percent,
347
    		$request_data->date_start,
348
    		$request_data->date_end,
349
    		$request_data->tva_tx,
350
    		$request_data->localtax1_tx,
351
    		$request_data->localtax2_tx,
352
    		'HT',
353
    		$request_data->info_bits,
354
    		$request_data->product_type,
355
    		$request_data->fk_parent_line,
356
    		0,
357
    		$request_data->fk_fournprice,
358
    		$request_data->pa_ht,
359
    		$request_data->label,
360
    		$request_data->special_code,
361
    		$request_data->array_options,
362
    		$request_data->situation_percent,
363
    		$request_data->fk_unit,
364
    		$request_data->multicurrency_subprice
365
    	);
366
367
    	if ($updateRes > 0) {
368
    		$result = $this->get($id);
369
    		unset($result->line);
370
    		return $this->_cleanObjectDatas($result);
371
	    } else {
372
	    	throw new RestException(304, $this->invoice->error);
373
    	}
374
    }
375
  
376
    /**
377
	 * Add a contact type of given invoice
378
	 *
379
	 * @param int    $id             Id of invoice to update
380
	 * @param int    $contactid      Id of contact to add
381
	 * @param string $type           Type of the contact (BILLING, SHIPPING, CUSTOMER)
382
	 *
383
	 * @url	POST {id}/contact/{contactid}/{type}
384
	 *
385
	 * @return int
386
     * @throws 401
387
     * @throws 404
388
	 */
389
    function postContact($id, $contactid, $type)
390
    {
391
        if(!DolibarrApiAccess::$user->rights->facture->creer) {
392
            throw new RestException(401);
393
        }
394
395
        $result = $this->invoice->fetch($id);
396
397
		if(!$result) {
398
			throw new RestException(404, 'Invoice not found');
399
		}
400
401
        if (!in_array($type, array('BILLING', 'SHIPPING', 'CUSTOMER'), true)) {
402
            throw new RestException(500, 'Availables types: BILLING, SHIPPING OR CUSTOMER');
403
        }
404
405
        if(!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
406
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
407
		}
408
409
        $result = $this->invoice->add_contact($contactid, $type, 'external');
410
411
        if (!$result) {
412
            throw new RestException(500, 'Error when added the contact');
413
        }
414
415
        return $this->_cleanObjectDatas($this->invoice);
416
    }
417
418
   /**
419
	 * Delete a contact type of given invoice
420
	 *
421
	 * @param int    $id             Id of invoice to update
422
	 * @param int    $rowid          Row key of the contact in the array contact_ids.
423
	 *
424
	 * @url	DELETE {id}/contact/{rowid}
425
	 *
426
	 * @return int
427
     * @throws 401
428
     * @throws 404
429
     * @throws 500
430
	 */
431
    function deleteContact($id, $rowid)
432
    {
433
        if(!DolibarrApiAccess::$user->rights->facture->creer) {
434
            throw new RestException(401);
435
        }
436
437
        $result = $this->invoice->fetch($id);
438
439
		if (!$result) {
440
			throw new RestException(404, 'Invoice not found');
441
		}
442
443
        if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
444
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
445
		}
446
447
        $result = $this->invoice->delete_contact($rowid);
448
449
        if (!$result) {
450
            throw new RestException(500, 'Error when deleted the contact');
451
        }
452
453
        return $this->_cleanObjectDatas($this->invoice);
454
    }
455
456
    /**
457
     * Deletes a line of a given invoice
458
     *
459
     * @param int   $id             Id of invoice
460
     * @param int   $lineid 		Id of the line to delete
461
     *
462
     * @url     DELETE {id}/lines/{lineid}
463
     *
464
     * @return array
465
     *
466
     * @throws 400
467
     * @throws 401
468
     * @throws 404
469
     * @throws 405
470
     */
471
    function deleteLine($id, $lineid)
472
    {
473
474
    	if(! DolibarrApiAccess::$user->rights->facture->creer) {
475
    		throw new RestException(401);
476
    	}
477
    	if(empty($lineid)) {
478
    		throw new RestException(400, 'Line ID is mandatory');
479
    	}
480
481
    	if( ! DolibarrApi::_checkAccessToResource('facture', $id)) {
482
    		throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
483
    	}
484
485
    	$result = $this->invoice->fetch($id);
486
    	if( ! $result ) {
487
    		throw new RestException(404, 'Invoice not found');
488
    	}
489
490
    	// TODO Check the lineid $lineid is a line of ojbect
491
492
    	$updateRes = $this->invoice->deleteline($lineid);
493
    	if ($updateRes > 0) {
494
    		return $this->get($id);
495
    	}
496
    	else
497
    	{
498
    		throw new RestException(405, $this->invoice->error);
499
    	}
500
    }
501
502
    /**
503
     * Update invoice
504
     *
505
     * @param int   $id             Id of invoice to update
506
     * @param array $request_data   Datas
507
     * @return int
508
     */
509
    function put($id, $request_data = null)
510
    {
511
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
512
			throw new RestException(401);
513
		}
514
515
        $result = $this->invoice->fetch($id);
516
        if( ! $result ) {
517
            throw new RestException(404, 'Invoice not found');
518
        }
519
520
		if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
521
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
522
		}
523
524
        foreach($request_data as $field => $value) {
525
            if ($field == 'id') continue;
526
            $this->invoice->$field = $value;
527
        }
528
529
        // update bank account
530
        if (!empty($this->invoice->fk_account))
531
        {
532
             if($this->invoice->setBankAccount($this->invoice->fk_account) == 0)
533
             {
534
                 throw new RestException(400, $this->invoice->error);
535
             }
536
        }
537
538
        if($this->invoice->update(DolibarrApiAccess::$user))
539
            return $this->get($id);
540
541
        return false;
542
    }
543
544
    /**
545
     * Delete invoice
546
     *
547
     * @param int   $id Invoice ID
548
     * @return array
549
     */
550
    function delete($id)
551
    {
552
        if(! DolibarrApiAccess::$user->rights->facture->supprimer) {
553
			throw new RestException(401);
554
		}
555
        $result = $this->invoice->fetch($id);
556
        if( ! $result ) {
557
            throw new RestException(404, 'Invoice not found');
558
        }
559
560
		if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
561
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
562
		}
563
564
        if( $this->invoice->delete($id) < 0)
565
        {
566
            throw new RestException(500);
567
        }
568
569
         return array(
570
            'success' => array(
571
                'code' => 200,
572
                'message' => 'Invoice deleted'
573
            )
574
        );
575
    }
576
577
    /**
578
     * Add a line to a given invoice
579
     *
580
     * Exemple of POST query :
581
     * {
582
     *     "desc": "Desc", "subprice": "1.00000000", "qty": "1", "tva_tx": "20.000", "localtax1_tx": "0.000", "localtax2_tx": "0.000",
583
     *     "fk_product": "1", "remise_percent": "0", "date_start": "", "date_end": "", "fk_code_ventilation": 0,  "info_bits": "0",
584
     *     "fk_remise_except": null,  "product_type": "1", "rang": "-1", "special_code": "0", "fk_parent_line": null, "fk_fournprice": null,
585
     *     "pa_ht": "0.00000000", "label": "", "array_options": [], "situation_percent": "100", "fk_prev_id": null, "fk_unit": null
586
     * }
587
     *
588
     * @param int   $id             Id of invoice
589
     * @param array $request_data   InvoiceLine data
590
     *
591
     * @url     POST {id}/lines
592
     *
593
     * @return int
594
     *
595
     * @throws 200
596
     * @throws 401
597
     * @throws 404
598
     * @throws 400
599
     */
600
    function postLine($id, $request_data = null)
601
    {
602
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
603
            throw new RestException(401);
604
        }
605
606
        $result = $this->invoice->fetch($id);
607
        if( ! $result ) {
608
            throw new RestException(404, 'Invoice not found');
609
        }
610
611
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
612
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
613
        }
614
615
        $request_data = (object) $request_data;
616
617
        // Reset fk_parent_line for no child products and special product
618
        if (($request_data->product_type != 9 && empty($request_data->fk_parent_line)) || $request_data->product_type == 9) {
619
            $request_data->fk_parent_line = 0;
620
        }
621
622
        // calculate pa_ht
623
        $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);
624
        $pa_ht = $marginInfos[0];
625
626
        $updateRes = $this->invoice->addline(
627
            $request_data->desc,
628
            $request_data->subprice,
629
            $request_data->qty,
630
            $request_data->tva_tx,
631
            $request_data->localtax1_tx,
632
            $request_data->localtax2_tx,
633
            $request_data->fk_product,
634
            $request_data->remise_percent,
635
            $request_data->date_start,
636
            $request_data->date_end,
637
            $request_data->fk_code_ventilation,
638
            $request_data->info_bits,
639
            $request_data->fk_remise_except,
640
            'HT',
641
            0,
642
            $request_data->product_type,
643
            $request_data->rang,
644
            $request_data->special_code,
645
            $request_data->origin,
646
            $request_data->origin_id,
647
            $request_data->fk_parent_line,
648
            empty($request_data->fk_fournprice)?null:$request_data->fk_fournprice,
649
            $pa_ht,
650
            $request_data->label,
651
            $request_data->array_options,
652
            $request_data->situation_percent,
653
            $request_data->fk_prev_id,
654
            $request_data->fk_unit
655
        );
656
657
        if ($updateRes < 0) {
658
            throw new RestException(400, 'Unable to insert the new line. Check your inputs. '.$this->invoice->error);
659
        }
660
661
        return $updateRes;
662
    }
663
664
    /**
665
     * Adds a contact to an invoice
666
     *
667
     * @param   int 	$id             	Order ID
668
     * @param   int 	$fk_socpeople       	Id of thirdparty contact (if source = 'external') or id of user (if souce = 'internal') to link
669
     * @param   string 	$type_contact           Type of contact (code). Must a code found into table llx_c_type_contact. For example: BILLING
670
     * @param   string  $source             	external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
671
     * @param   int     $notrigger              Disable all triggers
672
     *
673
     * @url POST    {id}/contacts
674
     *
675
     * @return  array
676
     *
677
     * @throws 200
678
     * @throws 304
679
     * @throws 401
680
     * @throws 404
681
     * @throws 500
682
     *
683
     */
684
    function addContact($id, $fk_socpeople, $type_contact, $source, $notrigger = 0)
685
    {
686
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
687
                throw new RestException(401);
688
        }
689
        $result = $this->invoice->fetch($id);
690
        if( ! $result ) {
691
                throw new RestException(404, 'Invoice not found');
692
        }
693
694
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
695
                throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
696
        }
697
698
        $result = $this->invoice->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
699
        if ($result < 0) {
700
                throw new RestException(500, 'Error : '.$this->invoice->error);
701
        }
702
703
        $result = $this->invoice->fetch($id);
704
        if( ! $result ) {
705
            throw new RestException(404, 'Invoice not found');
706
        }
707
708
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
709
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
710
        }
711
712
        return $this->_cleanObjectDatas($this->invoice);
713
    }
714
715
716
717
    /**
718
     * Sets an invoice as draft
719
     *
720
     * @param   int $id             Order ID
721
     * @param   int $idwarehouse    Warehouse ID
722
     *
723
     * @url POST    {id}/settodraft
724
     *
725
     * @return  array
726
     *
727
     * @throws 200
728
     * @throws 304
729
     * @throws 401
730
     * @throws 404
731
     * @throws 500
732
     *
733
     */
734
    function settodraft($id, $idwarehouse = -1)
735
    {
736
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
737
            throw new RestException(401);
738
        }
739
        $result = $this->invoice->fetch($id);
740
        if( ! $result ) {
741
            throw new RestException(404, 'Invoice not found');
742
        }
743
744
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
745
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
746
        }
747
748
        $result = $this->invoice->set_draft(DolibarrApiAccess::$user, $idwarehouse);
749
        if ($result == 0) {
750
            throw new RestException(304, 'Nothing done.');
751
        }
752
        if ($result < 0) {
753
            throw new RestException(500, 'Error : '.$this->invoice->error);
754
        }
755
756
        $result = $this->invoice->fetch($id);
757
        if( ! $result ) {
758
            throw new RestException(404, 'Invoice not found');
759
        }
760
761
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
762
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
763
        }
764
765
        return $this->_cleanObjectDatas($this->invoice);
766
    }
767
768
769
    /**
770
     * Validate an invoice
771
     *
772
	 * If you get a bad value for param notrigger check that ou provide this in body
773
     * {
774
     *   "idwarehouse": 0,
775
     *   "notrigger": 0
776
     * }
777
     *
778
     * @param   int $id             Invoice ID
779
     * @param   int $idwarehouse    Warehouse ID
780
     * @param   int $notrigger      1=Does not execute triggers, 0= execute triggers
781
     *
782
     * @url POST    {id}/validate
783
     *
784
     * @return  array
785
     */
786
    function validate($id, $idwarehouse = 0, $notrigger = 0)
787
    {
788
    	if(! DolibarrApiAccess::$user->rights->facture->creer) {
789
    		throw new RestException(401);
790
    	}
791
    	$result = $this->invoice->fetch($id);
792
    	if( ! $result ) {
793
    		throw new RestException(404, 'Invoice not found');
794
    	}
795
796
    	if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
797
    		throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
798
    	}
799
800
    	$result = $this->invoice->validate(DolibarrApiAccess::$user, '', $idwarehouse, $notrigger);
801
    	if ($result == 0) {
802
    		throw new RestException(304, 'Error nothing done. May be object is already validated');
803
    	}
804
    	if ($result < 0) {
805
    		throw new RestException(500, 'Error when validating Invoice: '.$this->invoice->error);
806
    	}
807
808
        $result = $this->invoice->fetch($id);
809
        if( ! $result ) {
810
            throw new RestException(404, 'Invoice not found');
811
        }
812
813
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
814
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
815
        }
816
817
        return $this->_cleanObjectDatas($this->invoice);
818
    }
819
820
    /**
821
     * Sets an invoice as paid
822
     *
823
     * @param   int 	$id            Order ID
824
     * @param   string 	$close_code    Code renseigne si on classe a payee completement alors que paiement incomplet (cas escompte par exemple)
825
     * @param   string 	$close_note    Commentaire renseigne si on classe a payee alors que paiement incomplet (cas escompte par exemple)
826
     *
827
     * @url POST    {id}/settopaid
828
     *
829
     * @return  array 	An invoice object
830
     *
831
     * @throws 200
832
     * @throws 304
833
     * @throws 401
834
     * @throws 404
835
     * @throws 500
836
     */
837
    function settopaid($id, $close_code = '', $close_note = '')
838
    {
839
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
840
            throw new RestException(401);
841
        }
842
        $result = $this->invoice->fetch($id);
843
        if( ! $result ) {
844
            throw new RestException(404, 'Invoice not found');
845
        }
846
847
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
848
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
849
        }
850
851
        $result = $this->invoice->set_paid(DolibarrApiAccess::$user, $close_code, $close_note);
852
        if ($result == 0) {
853
            throw new RestException(304, 'Error nothing done. May be object is already validated');
854
        }
855
        if ($result < 0) {
856
            throw new RestException(500, 'Error : '.$this->invoice->error);
857
        }
858
859
860
        $result = $this->invoice->fetch($id);
861
        if( ! $result ) {
862
            throw new RestException(404, 'Invoice not found');
863
        }
864
865
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
866
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
867
        }
868
869
        return $this->_cleanObjectDatas($this->invoice);
870
    }
871
872
873
    /**
874
     * Sets an invoice as unpaid
875
     *
876
     * @param   int     $id            Order ID
877
     *
878
     * @url POST    {id}/settounpaid
879
     *
880
     * @return  array   An invoice object
881
     *
882
     * @throws 200
883
     * @throws 304
884
     * @throws 401
885
     * @throws 404
886
     * @throws 500
887
     */
888
    function settounpaid($id)
889
    {
890
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
891
            throw new RestException(401);
892
        }
893
        $result = $this->invoice->fetch($id);
894
        if( ! $result ) {
895
            throw new RestException(404, 'Invoice not found');
896
        }
897
898
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
899
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
900
        }
901
902
        $result = $this->invoice->set_unpaid(DolibarrApiAccess::$user);
903
        if ($result == 0) {
904
            throw new RestException(304, 'Nothing done');
905
        }
906
        if ($result < 0) {
907
            throw new RestException(500, 'Error : '.$this->invoice->error);
908
        }
909
910
911
        $result = $this->invoice->fetch($id);
912
        if( ! $result ) {
913
            throw new RestException(404, 'Invoice not found');
914
        }
915
916
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
917
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
918
        }
919
920
        return $this->_cleanObjectDatas($this->invoice);
921
    }
922
923
   /**
924
     * Create a discount (credit available) for a credit note or a deposit.
925
     *
926
     * @param   int 	$id            Invoice ID
927
     * @url POST    {id}/markAsCreditAvailable
928
     *
929
     * @return  array 	An invoice object
930
     *
931
     * @throws 200
932
     * @throws 304
933
     * @throws 401
934
     * @throws 404
935
     * @throws 500
936
     */
937
    function markAsCreditAvailable($id)
938
    {
939
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
940
                throw new RestException(401);
941
        }
942
		
943
	    $this->db->begin();
944
		
945
        $result = $this->invoice->fetch($id);
946
        if( ! $result ) {
947
                throw new RestException(404, 'Invoice not found');
948
        }
949
950
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
951
                throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
952
        }
953
954
		$result = $this->invoice->fetch_thirdparty();
955
        if( ! $result ) {
956
                throw new RestException(404, 'Thirdparty not found');
957
        }
958
959
		if (! $this->invoice->paye)	// protection against multiple submit
960
		{
961
		   	$this->invoice->fetch_lines();
962
				
963
			// Loop on each vat rate
964
			$i=0;
965
			foreach($this->invoice->lines as $line)
966
			{
967
				$amount_ht[$line->tva_tx]+=$line->total_ht;
0 ignored issues
show
Bug introduced by
The variable $amount_ht does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
968
				$amount_tva[$line->tva_tx]+=$line->total_tva;
0 ignored issues
show
Bug introduced by
The variable $amount_tva does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
969
				$amount_ttc[$line->tva_tx]+=$line->total_ttc;
0 ignored issues
show
Bug introduced by
The variable $amount_ttc does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
970
				$i++;
971
			}
972
973
			// Insert one discount by VAT rate category
974
			$discount = new DiscountAbsolute($this->db);
975
			if ($this->invoice->type == 2)     $discount->description='(CREDIT_NOTE)';
976
			elseif ($this->invoice->type == 3) $discount->description='(DEPOSIT)';
977
			else {
978
				$this->error="CantConvertToReducAnInvoiceOfThisType";
979
				return -1;
980
			}
981
			$discount->tva_tx=abs($this->invoice->total_ttc);
982
			$discount->fk_soc=$this->invoice->socid;
983
			$discount->fk_facture_source=$this->invoice->id;
984
985
			$error=0;
986
			foreach($amount_ht as $tva_tx => $xxx)
987
			{
988
				$discount->amount_ht=abs($amount_ht[$tva_tx]);
989
				$discount->amount_tva=abs($amount_tva[$tva_tx]);
990
				$discount->amount_ttc=abs($amount_ttc[$tva_tx]);
991
				$discount->tva_tx=abs($tva_tx);
992
993
				$result=$discount->create(DolibarrApiAccess::$user);
994
				if ($result < 0)
995
				{
996
					$error++;
997
					break;
998
				}
999
			}
1000
1001
			if (! $error)
1002
			{
1003
				// Classe facture
1004
				$result=$this->invoice->set_paid(DolibarrApiAccess::$user);
1005
				if ($result > 0)
1006
				{
1007
					//$mesg='OK'.$discount->id;
1008
					$this->db->commit();
1009
				}
1010
				else
1011
				{
1012
					throw new RestException(500, 'Could not set paid');
1013
					$this->db->rollback();
0 ignored issues
show
Unused Code introduced by
$this->db->rollback(); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1014
				}
1015
			}
1016
			else
1017
			{
1018
				throw new RestException(500, 'Discount creation error');
1019
				$this->db->rollback();
0 ignored issues
show
Unused Code introduced by
$this->db->rollback(); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1020
			}
1021
		}
1022
1023
        $result = $this->invoice->fetch($id);
1024
        if( ! $result ) {
1025
            throw new RestException(404, 'Invoice not found');
1026
        }
1027
1028
        if( ! DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1029
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1030
        }
1031
1032
        return $this->_cleanObjectDatas($this->invoice);
1033
    }
1034
1035
     /**
1036
     * Add a discount line into an invoice (as an invoice line) using an existing absolute discount
1037
     *
1038
     * Note that this consume the discount.
1039
     *
1040
     * @param int   $id             Id of invoice
1041
     * @param int   $discountid     Id of discount
1042
     *
1043
     * @url     POST {id}/usediscount/{discountid}
1044
     *
1045
     * @return int
1046
     * @throws 400
1047
     * @throws 401
1048
     * @throws 404
1049
     * @throws 405
1050
     */
1051
    function useDiscount($id, $discountid)
1052
    {
1053
1054
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
1055
            throw new RestException(401);
1056
        }
1057
        if(empty($id)) {
1058
            throw new RestException(400, 'Invoice ID is mandatory');
1059
        }
1060
        if(empty($discountid)) {
1061
            throw new RestException(400, 'Discount ID is mandatory');
1062
        }
1063
1064
        if( ! DolibarrApi::_checkAccessToResource('facture', $id)) {
1065
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1066
        }
1067
1068
        $result = $this->invoice->fetch($id);
1069
        if( ! $result ) {
1070
            throw new RestException(404, 'Invoice not found');
1071
        }
1072
1073
        $result = $this->invoice->insert_discount($discountid);
1074
        if( $result < 0) {
1075
            throw new RestException(405, $this->invoice->error);
1076
        }
1077
1078
        return $result;
1079
    }
1080
1081
     /**
1082
     * Add an available credit note discount to payments of an existing invoice.
1083
     *
1084
     *  Note that this consume the credit note.
1085
     *
1086
     * @param int   $id            Id of invoice
1087
     * @param int   $discountid    Id of a discount coming from a credit note
1088
     *
1089
     * @url     POST {id}/usecreditnote/{discountid}
1090
     *
1091
     * @return int
1092
     * @throws 400
1093
     * @throws 401
1094
     * @throws 404
1095
     * @throws 405
1096
     */
1097
    function useCreditNote($id, $discountid)
1098
    {
1099
1100
        require_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php';
1101
1102
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
1103
            throw new RestException(401);
1104
        }
1105
        if(empty($id)) {
1106
            throw new RestException(400, 'Invoice ID is mandatory');
1107
        }
1108
        if(empty($discountid)) {
1109
            throw new RestException(400, 'Credit ID is mandatory');
1110
        }
1111
1112
        if( ! DolibarrApi::_checkAccessToResource('facture', $id)) {
1113
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1114
        }
1115
        $discount = new DiscountAbsolute($this->db);
1116
        $result = $discount->fetch($discountid);
1117
        if( ! $result ) {
1118
            throw new RestException(404, 'Credit not found');
1119
        }
1120
1121
        $result = $discount->link_to_invoice(0, $id);
1122
        if( $result < 0) {
1123
            throw new RestException(405, $discount->error);
1124
        }
1125
1126
        return $result;
1127
    }
1128
1129
    /**
1130
     * Get list of payments of a given invoice
1131
     *
1132
     * @param int   $id             Id of invoice
1133
     *
1134
     * @url     GET {id}/payments
1135
     *
1136
     * @return array
1137
     * @throws 400
1138
     * @throws 401
1139
     * @throws 404
1140
     * @throws 405
1141
     */
1142
    function getPayments($id)
1143
    {
1144
1145
        if(! DolibarrApiAccess::$user->rights->facture->lire) {
1146
            throw new RestException(401);
1147
        }
1148
        if(empty($id)) {
1149
            throw new RestException(400, 'Invoice ID is mandatory');
1150
        }
1151
1152
        if( ! DolibarrApi::_checkAccessToResource('facture', $id)) {
1153
            throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1154
        }
1155
1156
        $result = $this->invoice->fetch($id);
1157
        if( ! $result ) {
1158
            throw new RestException(404, 'Invoice not found');
1159
        }
1160
1161
        $result = $this->invoice->getListOfPayments();
1162
        if( $result < 0) {
1163
            throw new RestException(405, $this->invoice->error);
1164
        }
1165
1166
        return $result;
1167
    }
1168
1169
1170
    /**
1171
     * Add payment line to a specific invoice with the remain to pay as amount.
1172
     *
1173
     * @param int     $id                               Id of invoice
1174
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1175
     * @param int     $paiementid         {@from body}  Payment mode Id {@min 1}
1176
     * @param string  $closepaidinvoices  {@from body}  Close paid invoices {@choice yes,no}
1177
     * @param int     $accountid          {@from body}  Account Id {@min 1}
1178
     * @param string  $num_paiement       {@from body}  Payment number (optional)
1179
     * @param string  $comment            {@from body}  Note (optional)
1180
     * @param string  $chqemetteur        {@from body}  Payment issuer (mandatory if paiementcode = 'CHQ')
1181
     * @param string  $chqbank            {@from body}  Issuer bank name (optional)
1182
     *
1183
     * @url     POST {id}/payments
1184
     *
1185
     * @return int  Payment ID
1186
     * @throws 400
1187
     * @throws 401
1188
     * @throws 404
1189
     */
1190
    function addPayment($id, $datepaye, $paiementid, $closepaidinvoices, $accountid, $num_paiement = '', $comment = '', $chqemetteur = '', $chqbank = '')
1191
    {
1192
        global $conf;
1193
1194
    	require_once DOL_DOCUMENT_ROOT . '/compta/paiement/class/paiement.class.php';
1195
1196
    	if(! DolibarrApiAccess::$user->rights->facture->creer) {
1197
    		throw new RestException(403);
1198
    	}
1199
    	if(empty($id)) {
1200
    		throw new RestException(400, 'Invoice ID is mandatory');
1201
    	}
1202
1203
    	if( ! DolibarrApi::_checkAccessToResource('facture', $id)) {
1204
    		throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1205
    	}
1206
1207
    	if (! empty($conf->banque->enabled)) {
1208
    		if(empty($accountid)) {
1209
    			throw new RestException(400, 'Account ID is mandatory');
1210
    		}
1211
    	}
1212
1213
    	if(empty($paiementid)) {
1214
    		throw new RestException(400, 'Paiement ID or Paiement Code is mandatory');
1215
    	}
1216
1217
1218
    	$result = $this->invoice->fetch($id);
1219
    	if( ! $result ) {
1220
    		throw new RestException(404, 'Invoice not found');
1221
    	}
1222
1223
    	// Calculate amount to pay
1224
    	$totalpaye = $this->invoice->getSommePaiement();
1225
    	$totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
1226
    	$totaldeposits = $this->invoice->getSumDepositsUsed();
1227
    	$resteapayer = price2num($this->invoice->total_ttc - $totalpaye - $totalcreditnotes - $totaldeposits, 'MT');
1228
1229
    	$this->db->begin();
1230
1231
    	$amounts = array();
1232
    	$multicurrency_amounts = array();
1233
1234
    	// Clean parameters amount if payment is for a credit note
1235
    	if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1236
    		$resteapayer = price2num($resteapayer, 'MT');
1237
    		$amounts[$id] = -$resteapayer;
1238
    		// Multicurrency
1239
    		$newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1240
    		$multicurrency_amounts[$id] = -$newvalue;
1241
    	} else {
1242
    		$resteapayer = price2num($resteapayer, 'MT');
1243
    		$amounts[$id] = $resteapayer;
1244
    		// Multicurrency
1245
    		$newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1246
    		$multicurrency_amounts[$id] = $newvalue;
1247
    	}
1248
1249
1250
    	// Creation of payment line
1251
    	$paiement = new Paiement($this->db);
1252
    	$paiement->datepaye     = $datepaye;
1253
    	$paiement->amounts      = $amounts;                           // Array with all payments dispatching with invoice id
1254
    	$paiement->multicurrency_amounts = $multicurrency_amounts;    // Array with all payments dispatching
1255
    	$paiement->paiementid   = $paiementid;
1256
    	$paiement->paiementcode = dol_getIdFromCode($this->db, $paiementid, 'c_paiement', 'id', 'code', 1);
1257
    	$paiement->num_paiement = $num_paiement;
1258
    	$paiement->note         = $comment;
1259
1260
    	$paiement_id = $paiement->create(DolibarrApiAccess::$user, ($closepaidinvoices=='yes'?1:0));    // This include closing invoices
1261
    	if ($paiement_id < 0)
1262
    	{
1263
    		$this->db->rollback();
1264
    		throw new RestException(400, 'Payment error : '.$paiement->error);
1265
    	}
1266
1267
    	if (! empty($conf->banque->enabled)) {
1268
    		$label='(CustomerInvoicePayment)';
1269
1270
    		if($paiement->paiementcode == 'CHQ' && empty($chqemetteur)) {
1271
    			throw new RestException(400, 'Emetteur is mandatory when payment code is '.$paiement->paiementcode);
1272
    		}
1273
    		if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) $label='(CustomerInvoicePaymentBack)';  // Refund of a credit note
1274
    		$result=$paiement->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1275
    		if ($result < 0)
1276
    		{
1277
    			$this->db->rollback();
1278
    			throw new RestException(400, 'Add payment to bank error : '.$paiement->error);
1279
    		}
1280
    	}
1281
1282
    	$this->db->commit();
1283
1284
    	return $paiement_id;
1285
    }
1286
1287
    /**
1288
     * Add a payment to pay partially or completely one or several invoices.
1289
     * Warning: Take care that all invoices are owned by the same customer.
1290
     * Example of value for parameter arrayofamounts: {"1": "99.99", "2": "10"}
1291
     *
1292
     * @param array   $arrayofamounts     {@from body}  Array with id of invoices with amount to pay for each invoice
1293
     * @param string  $datepaye           {@from body}  Payment date        {@type timestamp}
1294
     * @param int     $paiementid         {@from body}  Payment mode Id {@min 1}
1295
     * @param string  $closepaidinvoices  {@from body}  Close paid invoices {@choice yes,no}
1296
     * @param int     $accountid          {@from body}  Account Id {@min 1}
1297
     * @param string  $num_paiement       {@from body}  Payment number (optional)
1298
     * @param string  $comment            {@from body}  Note (optional)
1299
     * @param string  $chqemetteur        {@from body}  Payment issuer (mandatory if paiementcode = 'CHQ')
1300
     * @param string  $chqbank            {@from body}  Issuer bank name (optional)
1301
     *
1302
     * @url     POST /paymentsdistributed
1303
     *
1304
     * @return int  Payment ID
1305
     * @throws 400
1306
     * @throws 401
1307
     * @throws 403
1308
     * @throws 404
1309
     */
1310
    function addPaymentDistributed($arrayofamounts, $datepaye, $paiementid, $closepaidinvoices, $accountid, $num_paiement = '', $comment = '', $chqemetteur = '', $chqbank = '')
1311
    {
1312
        global $conf;
1313
1314
        require_once DOL_DOCUMENT_ROOT . '/compta/paiement/class/paiement.class.php';
1315
1316
        if(! DolibarrApiAccess::$user->rights->facture->creer) {
1317
            throw new RestException(403);
1318
        }
1319
        foreach($arrayofamounts as $id => $amount) {
1320
        	if(empty($id)) {
1321
        		throw new RestException(400, 'Invoice ID is mandatory. Fill the invoice id and amount into arrayofamounts parameter. For example: {"1": "99.99", "2": "10"}');
1322
        	}
1323
        	if( ! DolibarrApi::_checkAccessToResource('facture', $id)) {
1324
        		throw new RestException(403, 'Access not allowed on invoice ID '.$id.' for login '.DolibarrApiAccess::$user->login);
1325
        	}
1326
        }
1327
1328
        if (! empty($conf->banque->enabled)) {
1329
        	if(empty($accountid)) {
1330
        		throw new RestException(400, 'Account ID is mandatory');
1331
        	}
1332
        }
1333
        if(empty($paiementid)) {
1334
        	throw new RestException(400, 'Paiement ID or Paiement Code is mandatory');
1335
        }
1336
1337
        $this->db->begin();
1338
1339
        $amounts = array();
1340
        $multicurrency_amounts = array();
1341
1342
        // Loop on each invoice to pay
1343
        foreach($arrayofamounts as $id => $amount)
1344
        {
1345
        	$result = $this->invoice->fetch($id);
1346
        	if( ! $result ) {
1347
        		$this->db->rollback();
1348
        		throw new RestException(404, 'Invoice ID '.$id.' not found');
1349
        	}
1350
1351
        	// Calculate amount to pay
1352
        	$totalpaye = $this->invoice->getSommePaiement();
1353
        	$totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
1354
        	$totaldeposits = $this->invoice->getSumDepositsUsed();
1355
        	$resteapayer = price2num($this->invoice->total_ttc - $totalpaye - $totalcreditnotes - $totaldeposits, 'MT');
1356
        	if ($amount != 'remain')
1357
        	{
1358
        		if ($amount > $resteapayer)
1359
        		{
1360
        			$this->db->rollback();
1361
        			throw new RestException(400, 'Payment amount on invoice ID '.$id.' ('.$amount.') is higher than remain to pay ('.$resteapayer.')');
1362
        		}
1363
        		$resteapayer = $amount;
1364
        	}
1365
            // Clean parameters amount if payment is for a credit note
1366
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1367
                $resteapayer = price2num($resteapayer, 'MT');
1368
                $amounts[$id] = -$resteapayer;
1369
                // Multicurrency
1370
                $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1371
                $multicurrency_amounts[$id] = -$newvalue;
1372
            } else {
1373
                $resteapayer = price2num($resteapayer, 'MT');
1374
                $amounts[$id] = $resteapayer;
1375
                // Multicurrency
1376
                $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1377
                $multicurrency_amounts[$id] = $newvalue;
1378
            }
1379
        }
1380
1381
        // Creation of payment line
1382
        $paiement = new Paiement($this->db);
1383
        $paiement->datepaye     = $datepaye;
1384
        $paiement->amounts      = $amounts;                           // Array with all payments dispatching with invoice id
1385
        $paiement->multicurrency_amounts = $multicurrency_amounts;    // Array with all payments dispatching
1386
        $paiement->paiementid   = $paiementid;
1387
        $paiement->paiementcode = dol_getIdFromCode($this->db, $paiementid, 'c_paiement', 'id', 'code', 1);
1388
        $paiement->num_paiement = $num_paiement;
1389
        $paiement->note         = $comment;
1390
        $paiement_id = $paiement->create(DolibarrApiAccess::$user, ($closepaidinvoices=='yes'?1:0));    // This include closing invoices
1391
        if ($paiement_id < 0)
1392
        {
1393
            $this->db->rollback();
1394
            throw new RestException(400, 'Payment error : '.$paiement->error);
1395
        }
1396
        if (! empty($conf->banque->enabled)) {
1397
            $label='(CustomerInvoicePayment)';
1398
            if($paiement->paiementcode == 'CHQ' && empty($chqemetteur)) {
1399
                  throw new RestException(400, 'Emetteur is mandatory when payment code is '.$paiement->paiementcode);
1400
            }
1401
            if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) $label='(CustomerInvoicePaymentBack)';  // Refund of a credit note
1402
            $result=$paiement->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1403
            if ($result < 0)
1404
            {
1405
                $this->db->rollback();
1406
                throw new RestException(400, 'Add payment to bank error : '.$paiement->error);
1407
            }
1408
        }
1409
1410
        $this->db->commit();
1411
1412
        return $paiement_id;
1413
    }
1414
1415
    /**
1416
     * Clean sensible object datas
1417
     *
1418
     * @param   object  $object    Object to clean
1419
     * @return    array    Array of cleaned object properties
1420
     */
1421
    function _cleanObjectDatas($object)
1422
    {
1423
1424
        $object = parent::_cleanObjectDatas($object);
1425
1426
        unset($object->note);
1427
        unset($object->address);
1428
        unset($object->barcode_type);
1429
        unset($object->barcode_type_code);
1430
        unset($object->barcode_type_label);
1431
        unset($object->barcode_type_coder);
1432
1433
        return $object;
1434
    }
1435
1436
    /**
1437
     * Validate fields before create or update object
1438
     *
1439
     * @param array|null    $data       Datas to validate
1440
     * @return array
1441
     *
1442
     * @throws RestException
1443
     */
1444
    function _validate($data)
1445
    {
1446
        $invoice = array();
1447
        foreach (Invoices::$FIELDS as $field) {
1448
            if (!isset($data[$field])) {
1449
                throw new RestException(400, "$field field missing");
1450
            }
1451
            $invoice[$field] = $data[$field];
1452
        }
1453
        return $invoice;
1454
    }
1455
}
1456