dolibarr  20.0.0-alpha
api_invoices.class.php
1 <?php
2 /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
3  * Copyright (C) 2020 Thibault FOUCART <support@ptibogxiv.net>
4  * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
5  * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
6  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 use Luracast\Restler\RestException;
23 
24 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
25 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
26 
27 
34 class Invoices extends DolibarrApi
35 {
40  public static $FIELDS = array(
41  'socid',
42  );
43 
47  private $invoice;
48 
52  private $template_invoice;
53 
54 
58  public function __construct()
59  {
60  global $db;
61  $this->db = $db;
62  $this->invoice = new Facture($this->db);
63  $this->template_invoice = new FactureRec($this->db);
64  }
65 
77  public function get($id, $contact_list = 1)
78  {
79  return $this->_fetch($id, '', '', $contact_list);
80  }
81 
95  public function getByRef($ref, $contact_list = 1)
96  {
97  return $this->_fetch('', $ref, '', $contact_list);
98  }
99 
113  public function getByRefExt($ref_ext, $contact_list = 1)
114  {
115  return $this->_fetch('', '', $ref_ext, $contact_list);
116  }
117 
131  private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = 1)
132  {
133  if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
134  throw new RestException(403);
135  }
136 
137  $result = $this->invoice->fetch($id, $ref, $ref_ext);
138  if (!$result) {
139  throw new RestException(404, 'Invoice not found');
140  }
141 
142  // Get payment details
143  $this->invoice->totalpaid = $this->invoice->getSommePaiement();
144  $this->invoice->totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
145  $this->invoice->totaldeposits = $this->invoice->getSumDepositsUsed();
146  $this->invoice->remaintopay = price2num($this->invoice->total_ttc - $this->invoice->totalpaid - $this->invoice->totalcreditnotes - $this->invoice->totaldeposits, 'MT');
147 
148  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
149  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
150  }
151 
152  // Add external contacts ids
153  if ($contact_list > -1) {
154  $tmparray = $this->invoice->liste_contact(-1, 'external', $contact_list);
155  if (is_array($tmparray)) {
156  $this->invoice->contacts_ids = $tmparray;
157  }
158  }
159 
160  $this->invoice->fetchObjectLinked();
161 
162  // Add online_payment_url, copied from order
163  require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
164  $this->invoice->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $this->invoice->ref);
165 
166  return $this->_cleanObjectDatas($this->invoice);
167  }
168 
187  public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $status = '', $sqlfilters = '', $properties = '')
188  {
189  if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
190  throw new RestException(403);
191  }
192 
193  $obj_ret = array();
194 
195  // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
196  $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
197 
198  // If the internal user must only see his customers, force searching by him
199  $search_sale = 0;
200  if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
201  $search_sale = DolibarrApiAccess::$user->id;
202  }
203 
204  $sql = "SELECT t.rowid";
205  $sql .= " FROM ".MAIN_DB_PREFIX."facture AS t";
206  $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
207  $sql .= ' WHERE t.entity IN ('.getEntity('invoice').')';
208  if ($socids) {
209  $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
210  }
211  // Search on sale representative
212  if ($search_sale && $search_sale != '-1') {
213  if ($search_sale == -2) {
214  $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
215  } elseif ($search_sale > 0) {
216  $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).")";
217  }
218  }
219  // Filter by status
220  if ($status == 'draft') {
221  $sql .= " AND t.fk_statut IN (0)";
222  }
223  if ($status == 'unpaid') {
224  $sql .= " AND t.fk_statut IN (1)";
225  }
226  if ($status == 'paid') {
227  $sql .= " AND t.fk_statut IN (2)";
228  }
229  if ($status == 'cancelled') {
230  $sql .= " AND t.fk_statut IN (3)";
231  }
232  // Add sql filters
233  if ($sqlfilters) {
234  $errormessage = '';
235  $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
236  if ($errormessage) {
237  throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
238  }
239  }
240 
241  $sql .= $this->db->order($sortfield, $sortorder);
242  if ($limit) {
243  if ($page < 0) {
244  $page = 0;
245  }
246  $offset = $limit * $page;
247 
248  $sql .= $this->db->plimit($limit + 1, $offset);
249  }
250 
251  $result = $this->db->query($sql);
252  if ($result) {
253  $i = 0;
254  $num = $this->db->num_rows($result);
255  $min = min($num, ($limit <= 0 ? $num : $limit));
256  while ($i < $min) {
257  $obj = $this->db->fetch_object($result);
258  $invoice_static = new Facture($this->db);
259  if ($invoice_static->fetch($obj->rowid)) {
260  // Get payment details
261  $invoice_static->totalpaid = $invoice_static->getSommePaiement();
262  $invoice_static->totalcreditnotes = $invoice_static->getSumCreditNotesUsed();
263  $invoice_static->totaldeposits = $invoice_static->getSumDepositsUsed();
264  $invoice_static->remaintopay = price2num($invoice_static->total_ttc - $invoice_static->totalpaid - $invoice_static->totalcreditnotes - $invoice_static->totaldeposits, 'MT');
265 
266  // Add external contacts ids
267  $tmparray = $invoice_static->liste_contact(-1, 'external', 1);
268  if (is_array($tmparray)) {
269  $invoice_static->contacts_ids = $tmparray;
270  }
271  // Add online_payment_url, copied from order
272  require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
273  $invoice_static->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $invoice_static->ref);
274 
275  $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($invoice_static), $properties);
276  }
277  $i++;
278  }
279  } else {
280  throw new RestException(503, 'Error when retrieve invoice list : '.$this->db->lasterror());
281  }
282 
283  return $obj_ret;
284  }
285 
292  public function post($request_data = null)
293  {
294  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
295  throw new RestException(403, "Insuffisant rights");
296  }
297  // Check mandatory fields
298  $result = $this->_validate($request_data);
299 
300  foreach ($request_data as $field => $value) {
301  if ($field === 'caller') {
302  // 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
303  $this->invoice->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
304  continue;
305  }
306 
307  $this->invoice->$field = $this->_checkValForAPI($field, $value, $this->invoice);
308  }
309  if (!array_key_exists('date', $request_data)) {
310  $this->invoice->date = dol_now();
311  }
312  /* We keep lines as an array
313  if (isset($request_data["lines"])) {
314  $lines = array();
315  foreach ($request_data["lines"] as $line) {
316  array_push($lines, (object) $line);
317  }
318  $this->invoice->lines = $lines;
319  }*/
320 
321  if ($this->invoice->create(DolibarrApiAccess::$user, 0, (empty($request_data["date_lim_reglement"]) ? 0 : $request_data["date_lim_reglement"])) < 0) {
322  throw new RestException(500, "Error creating invoice", array_merge(array($this->invoice->error), $this->invoice->errors));
323  }
324  return ((int) $this->invoice->id);
325  }
326 
340  public function createInvoiceFromOrder($orderid)
341  {
342  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
343 
344  if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
345  throw new RestException(403);
346  }
347  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
348  throw new RestException(403);
349  }
350  if (empty($orderid)) {
351  throw new RestException(400, 'Order ID is mandatory');
352  }
353 
354  $order = new Commande($this->db);
355  $result = $order->fetch($orderid);
356  if (!$result) {
357  throw new RestException(404, 'Order not found');
358  }
359 
360  $result = $this->invoice->createFromOrder($order, DolibarrApiAccess::$user);
361  if ($result < 0) {
362  throw new RestException(405, $this->invoice->error);
363  }
364  $this->invoice->fetchObjectLinked();
365  return $this->_cleanObjectDatas($this->invoice);
366  }
367 
381  public function createInvoiceFromContract($contractid)
382  {
383  require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
384 
385  if (!DolibarrApiAccess::$user->hasRight('contrat', 'lire')) {
386  throw new RestException(403);
387  }
388  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
389  throw new RestException(403);
390  }
391  if (empty($contractid)) {
392  throw new RestException(400, 'Contract ID is mandatory');
393  }
394 
395  $contract = new Contrat($this->db);
396  $result = $contract->fetch($contractid);
397  if (!$result) {
398  throw new RestException(404, 'Contract not found');
399  }
400 
401  $result = $this->invoice->createFromContract($contract, DolibarrApiAccess::$user);
402  if ($result < 0) {
403  throw new RestException(405, $this->invoice->error);
404  }
405  $this->invoice->fetchObjectLinked();
406  return $this->_cleanObjectDatas($this->invoice);
407  }
408 
417  public function getLines($id)
418  {
419  if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
420  throw new RestException(403);
421  }
422 
423  $result = $this->invoice->fetch($id);
424  if (!$result) {
425  throw new RestException(404, 'Invoice not found');
426  }
427 
428  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
429  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
430  }
431  $this->invoice->getLinesArray();
432  $result = array();
433  foreach ($this->invoice->lines as $line) {
434  array_push($result, $this->_cleanObjectDatas($line));
435  }
436  return $result;
437  }
438 
453  public function putLine($id, $lineid, $request_data = null)
454  {
455  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
456  throw new RestException(403);
457  }
458 
459  $result = $this->invoice->fetch($id);
460  if (!$result) {
461  throw new RestException(404, 'Invoice not found');
462  }
463 
464  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
465  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
466  }
467 
468  $request_data = (object) $request_data;
469 
470  $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
471  $request_data->label = sanitizeVal($request_data->label);
472 
473  $updateRes = $this->invoice->updateline(
474  $lineid,
475  $request_data->desc,
476  $request_data->subprice,
477  $request_data->qty,
478  $request_data->remise_percent,
479  $request_data->date_start,
480  $request_data->date_end,
481  $request_data->tva_tx,
482  $request_data->localtax1_tx,
483  $request_data->localtax2_tx,
484  $request_data->price_base_type ? $request_data->price_base_type : 'HT',
485  $request_data->info_bits,
486  $request_data->product_type,
487  $request_data->fk_parent_line,
488  0,
489  $request_data->fk_fournprice,
490  $request_data->pa_ht,
491  $request_data->label,
492  $request_data->special_code,
493  $request_data->array_options,
494  $request_data->situation_percent,
495  $request_data->fk_unit,
496  $request_data->multicurrency_subprice,
497  0,
498  $request_data->ref_ext,
499  $request_data->rang
500  );
501 
502  if ($updateRes > 0) {
503  $result = $this->get($id);
504  unset($result->line);
505  return $this->_cleanObjectDatas($result);
506  } else {
507  throw new RestException(304, $this->invoice->error);
508  }
509  }
510 
524  public function postContact($id, $contactid, $type)
525  {
526  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
527  throw new RestException(403);
528  }
529 
530  $result = $this->invoice->fetch($id);
531 
532  if (!$result) {
533  throw new RestException(404, 'Invoice not found');
534  }
535 
536  if (!in_array($type, array('BILLING', 'SHIPPING', 'CUSTOMER'), true)) {
537  throw new RestException(500, 'Availables types: BILLING, SHIPPING OR CUSTOMER');
538  }
539 
540  if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
541  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
542  }
543 
544  $result = $this->invoice->add_contact($contactid, $type, 'external');
545 
546  if (!$result) {
547  throw new RestException(500, 'Error when added the contact');
548  }
549 
550  return array(
551  'success' => array(
552  'code' => 200,
553  'message' => 'Contact linked to the invoice'
554  )
555  );
556  }
557 
572  public function deleteContact($id, $contactid, $type)
573  {
574  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
575  throw new RestException(403);
576  }
577 
578  $result = $this->invoice->fetch($id);
579 
580  if (!$result) {
581  throw new RestException(404, 'Invoice not found');
582  }
583 
584  if (!DolibarrApi::_checkAccessToResource('invoice', $this->invoice->id)) {
585  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
586  }
587 
588  $contacts = $this->invoice->liste_contact();
589 
590  foreach ($contacts as $contact) {
591  if ($contact['id'] == $contactid && $contact['code'] == $type) {
592  $result = $this->invoice->delete_contact($contact['rowid']);
593 
594  if (!$result) {
595  throw new RestException(500, 'Error when deleted the contact');
596  }
597  }
598  }
599 
600  return $this->_cleanObjectDatas($this->invoice);
601  }
602 
617  public function deleteLine($id, $lineid)
618  {
619  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
620  throw new RestException(403);
621  }
622  if (empty($lineid)) {
623  throw new RestException(400, 'Line ID is mandatory');
624  }
625 
626  if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
627  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
628  }
629 
630  $result = $this->invoice->fetch($id);
631  if (!$result) {
632  throw new RestException(404, 'Invoice not found');
633  }
634 
635  $updateRes = $this->invoice->deleteLine($lineid, $id);
636  if ($updateRes > 0) {
637  return $this->get($id);
638  } else {
639  throw new RestException(405, $this->invoice->error);
640  }
641  }
642 
650  public function put($id, $request_data = null)
651  {
652  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
653  throw new RestException(403);
654  }
655 
656  $result = $this->invoice->fetch($id);
657  if (!$result) {
658  throw new RestException(404, 'Invoice not found');
659  }
660 
661  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
662  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
663  }
664 
665  foreach ($request_data as $field => $value) {
666  if ($field == 'id') {
667  continue;
668  }
669  if ($field === 'caller') {
670  // 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
671  $this->invoice->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
672  continue;
673  }
674  if ($field == 'array_options' && is_array($value)) {
675  foreach ($value as $index => $val) {
676  $this->invoice->array_options[$index] = $this->_checkValForAPI($field, $val, $this->invoice);
677  }
678  continue;
679  }
680 
681  $this->invoice->$field = $this->_checkValForAPI($field, $value, $this->invoice);
682 
683  // If cond reglement => update date lim reglement
684  if ($field == 'cond_reglement_id') {
685  $this->invoice->date_lim_reglement = $this->invoice->calculate_date_lim_reglement();
686  }
687  }
688 
689  // update bank account
690  if (!empty($this->invoice->fk_account)) {
691  if ($this->invoice->setBankAccount($this->invoice->fk_account) == 0) {
692  throw new RestException(400, $this->invoice->error);
693  }
694  }
695 
696  if ($this->invoice->update(DolibarrApiAccess::$user)) {
697  return $this->get($id);
698  }
699 
700  return false;
701  }
702 
709  public function delete($id)
710  {
711  if (!DolibarrApiAccess::$user->hasRight('facture', 'supprimer')) {
712  throw new RestException(403);
713  }
714  $result = $this->invoice->fetch($id);
715  if (!$result) {
716  throw new RestException(404, 'Invoice not found');
717  }
718 
719  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
720  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
721  }
722 
723  $result = $this->invoice->delete(DolibarrApiAccess::$user);
724  if ($result < 0) {
725  throw new RestException(500, 'Error when deleting invoice');
726  } elseif ($result == 0) {
727  throw new RestException(403, 'Invoice not erasable');
728  }
729 
730  return array(
731  'success' => array(
732  'code' => 200,
733  'message' => 'Invoice deleted'
734  )
735  );
736  }
737 
761  public function postLine($id, $request_data = null)
762  {
763  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
764  throw new RestException(403);
765  }
766 
767  $result = $this->invoice->fetch($id);
768  if (!$result) {
769  throw new RestException(404, 'Invoice not found');
770  }
771 
772  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
773  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
774  }
775 
776  $request_data = (object) $request_data;
777 
778  $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
779  $request_data->label = sanitizeVal($request_data->label);
780 
781  // Reset fk_parent_line for no child products and special product
782  if (($request_data->product_type != 9 && empty($request_data->fk_parent_line)) || $request_data->product_type == 9) {
783  $request_data->fk_parent_line = 0;
784  }
785 
786  // calculate pa_ht
787  $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);
788  $pa_ht = $marginInfos[0];
789 
790  $updateRes = $this->invoice->addline(
791  $request_data->desc,
792  $request_data->subprice,
793  $request_data->qty,
794  $request_data->tva_tx,
795  $request_data->localtax1_tx,
796  $request_data->localtax2_tx,
797  $request_data->fk_product,
798  $request_data->remise_percent,
799  $request_data->date_start,
800  $request_data->date_end,
801  $request_data->fk_code_ventilation,
802  $request_data->info_bits,
803  $request_data->fk_remise_except,
804  $request_data->price_base_type ? $request_data->price_base_type : 'HT',
805  $request_data->subprice,
806  $request_data->product_type,
807  $request_data->rang,
808  $request_data->special_code,
809  $request_data->origin,
810  $request_data->origin_id,
811  $request_data->fk_parent_line,
812  empty($request_data->fk_fournprice) ? null : $request_data->fk_fournprice,
813  $pa_ht,
814  $request_data->label,
815  $request_data->array_options,
816  $request_data->situation_percent,
817  $request_data->fk_prev_id,
818  $request_data->fk_unit,
819  0,
820  $request_data->ref_ext
821  );
822 
823  if ($updateRes < 0) {
824  throw new RestException(400, 'Unable to insert the new line. Check your inputs. '.$this->invoice->error);
825  }
826 
827  return $updateRes;
828  }
829 
849  public function addContact($id, $fk_socpeople, $type_contact, $source, $notrigger = 0)
850  {
851  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
852  throw new RestException(403);
853  }
854  $result = $this->invoice->fetch($id);
855  if (!$result) {
856  throw new RestException(404, 'Invoice not found');
857  }
858 
859  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
860  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
861  }
862 
863  $result = $this->invoice->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
864  if ($result < 0) {
865  throw new RestException(500, 'Error : '.$this->invoice->error);
866  }
867 
868  $result = $this->invoice->fetch($id);
869  if (!$result) {
870  throw new RestException(404, 'Invoice not found');
871  }
872 
873  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
874  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
875  }
876 
877  return $this->_cleanObjectDatas($this->invoice);
878  }
879 
880 
881 
897  public function settodraft($id, $idwarehouse = -1)
898  {
899  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
900  throw new RestException(403);
901  }
902  $result = $this->invoice->fetch($id);
903  if (!$result) {
904  throw new RestException(404, 'Invoice not found');
905  }
906 
907  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
908  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
909  }
910 
911  $result = $this->invoice->setDraft(DolibarrApiAccess::$user, $idwarehouse);
912  if ($result == 0) {
913  throw new RestException(304, 'Nothing done.');
914  }
915  if ($result < 0) {
916  throw new RestException(500, 'Error : '.$this->invoice->error);
917  }
918 
919  $result = $this->invoice->fetch($id);
920  if (!$result) {
921  throw new RestException(404, 'Invoice not found');
922  }
923 
924  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
925  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
926  }
927 
928  return $this->_cleanObjectDatas($this->invoice);
929  }
930 
931 
949  public function validate($id, $force_number = '', $idwarehouse = 0, $notrigger = 0)
950  {
951  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
952  throw new RestException(403);
953  }
954  $result = $this->invoice->fetch($id);
955  if (!$result) {
956  throw new RestException(404, 'Invoice not found');
957  }
958 
959  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
960  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
961  }
962 
963  $result = $this->invoice->validate(DolibarrApiAccess::$user, $force_number, $idwarehouse, $notrigger);
964  if ($result == 0) {
965  throw new RestException(304, 'Error nothing done. May be object is already validated');
966  }
967  if ($result < 0) {
968  throw new RestException(500, 'Error when validating Invoice: '.$this->invoice->error);
969  }
970 
971  $result = $this->invoice->fetch($id);
972  if (!$result) {
973  throw new RestException(404, 'Invoice not found');
974  }
975 
976  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
977  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
978  }
979 
980  // copy from order
981  require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
982  $this->invoice->online_payment_url = getOnlinePaymentUrl(0, 'invoice', $this->invoice->ref);
983 
984  return $this->_cleanObjectDatas($this->invoice);
985  }
986 
1002  public function settopaid($id, $close_code = '', $close_note = '')
1003  {
1004  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1005  throw new RestException(403);
1006  }
1007  $result = $this->invoice->fetch($id);
1008  if (!$result) {
1009  throw new RestException(404, 'Invoice not found');
1010  }
1011 
1012  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1013  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1014  }
1015 
1016  $result = $this->invoice->setPaid(DolibarrApiAccess::$user, $close_code, $close_note);
1017  if ($result == 0) {
1018  throw new RestException(304, 'Error nothing done. May be object is already validated');
1019  }
1020  if ($result < 0) {
1021  throw new RestException(500, 'Error : '.$this->invoice->error);
1022  }
1023 
1024 
1025  $result = $this->invoice->fetch($id);
1026  if (!$result) {
1027  throw new RestException(404, 'Invoice not found');
1028  }
1029 
1030  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1031  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1032  }
1033 
1034  return $this->_cleanObjectDatas($this->invoice);
1035  }
1036 
1037 
1051  public function settounpaid($id)
1052  {
1053  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1054  throw new RestException(403);
1055  }
1056  $result = $this->invoice->fetch($id);
1057  if (!$result) {
1058  throw new RestException(404, 'Invoice not found');
1059  }
1060 
1061  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1062  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1063  }
1064 
1065  $result = $this->invoice->setUnpaid(DolibarrApiAccess::$user);
1066  if ($result == 0) {
1067  throw new RestException(304, 'Nothing done');
1068  }
1069  if ($result < 0) {
1070  throw new RestException(500, 'Error : '.$this->invoice->error);
1071  }
1072 
1073 
1074  $result = $this->invoice->fetch($id);
1075  if (!$result) {
1076  throw new RestException(404, 'Invoice not found');
1077  }
1078 
1079  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1080  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1081  }
1082 
1083  return $this->_cleanObjectDatas($this->invoice);
1084  }
1085 
1094  public function getDiscount($id)
1095  {
1096  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1097 
1098  if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1099  throw new RestException(403);
1100  }
1101 
1102  $result = $this->invoice->fetch($id);
1103  if (!$result) {
1104  throw new RestException(404, 'Invoice not found');
1105  }
1106 
1107  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1108  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1109  }
1110 
1111  $discountcheck = new DiscountAbsolute($this->db);
1112  $result = $discountcheck->fetch(0, $this->invoice->id);
1113 
1114  if ($result == 0) {
1115  throw new RestException(404, 'Discount not found');
1116  }
1117  if ($result < 0) {
1118  throw new RestException(500, $discountcheck->error);
1119  }
1120 
1121  return parent::_cleanObjectDatas($discountcheck);
1122  }
1123 
1137  public function markAsCreditAvailable($id)
1138  {
1139  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1140 
1141  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1142  throw new RestException(403);
1143  }
1144 
1145  $result = $this->invoice->fetch($id);
1146  if (!$result) {
1147  throw new RestException(404, 'Invoice not found');
1148  }
1149 
1150  if (!DolibarrApi::_checkAccessToResource('facture', $this->invoice->id)) {
1151  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1152  }
1153 
1154  if ($this->invoice->paye) {
1155  throw new RestException(500, 'Alreay paid');
1156  }
1157 
1158  $this->invoice->fetch($id);
1159  $this->invoice->fetch_thirdparty();
1160 
1161  // Check if there is already a discount (protection to avoid duplicate creation when resubmit post)
1162  $discountcheck = new DiscountAbsolute($this->db);
1163  $result = $discountcheck->fetch(0, $this->invoice->id);
1164 
1165  $canconvert = 0;
1166  if ($this->invoice->type == Facture::TYPE_DEPOSIT && empty($discountcheck->id)) {
1167  $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)
1168  }
1169  if (($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_STANDARD) && $this->invoice->paye == 0 && empty($discountcheck->id)) {
1170  $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)
1171  }
1172  if ($canconvert) {
1173  $this->db->begin();
1174 
1175  $amount_ht = $amount_tva = $amount_ttc = array();
1176  $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
1177 
1178  // Loop on each vat rate
1179  $i = 0;
1180  foreach ($this->invoice->lines as $line) {
1181  if ($line->product_type < 9 && $line->total_ht != 0) { // Remove lines with product_type greater than or equal to 9
1182  // no need to create discount if amount is null
1183  $amount_ht[$line->tva_tx] += $line->total_ht;
1184  $amount_tva[$line->tva_tx] += $line->total_tva;
1185  $amount_ttc[$line->tva_tx] += $line->total_ttc;
1186  $multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht;
1187  $multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva;
1188  $multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc;
1189  $i++;
1190  }
1191  }
1192 
1193  // Insert one discount by VAT rate category
1194  $discount = new DiscountAbsolute($this->db);
1195  if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1196  $discount->description = '(CREDIT_NOTE)';
1197  } elseif ($this->invoice->type == Facture::TYPE_DEPOSIT) {
1198  $discount->description = '(DEPOSIT)';
1199  } elseif ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1200  $discount->description = '(EXCESS RECEIVED)';
1201  } else {
1202  throw new RestException(500, 'Cant convert to reduc an Invoice of this type');
1203  }
1204 
1205  $discount->fk_soc = $this->invoice->socid;
1206  $discount->socid = $this->invoice->socid;
1207  $discount->fk_facture_source = $this->invoice->id;
1208 
1209  $error = 0;
1210 
1211  if ($this->invoice->type == Facture::TYPE_STANDARD || $this->invoice->type == Facture::TYPE_REPLACEMENT || $this->invoice->type == Facture::TYPE_SITUATION) {
1212  // If we're on a standard invoice, we have to get excess received to create a discount in TTC without VAT
1213 
1214  // Total payments
1215  $sql = 'SELECT SUM(pf.amount) as total_payments';
1216  $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p';
1217  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
1218  $sql .= ' WHERE pf.fk_facture = '.((int) $this->invoice->id);
1219  $sql .= ' AND pf.fk_paiement = p.rowid';
1220  $sql .= ' AND p.entity IN ('.getEntity('invoice').')';
1221  $resql = $this->db->query($sql);
1222  if (!$resql) {
1223  dol_print_error($this->db);
1224  }
1225 
1226  $res = $this->db->fetch_object($resql);
1227  $total_payments = $res->total_payments;
1228 
1229  // Total credit note and deposit
1230  $total_creditnote_and_deposit = 0;
1231  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1232  $sql .= " re.description, re.fk_facture_source";
1233  $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
1234  $sql .= " WHERE fk_facture = ".((int) $this->invoice->id);
1235  $resql = $this->db->query($sql);
1236  if (!empty($resql)) {
1237  while ($obj = $this->db->fetch_object($resql)) {
1238  $total_creditnote_and_deposit += $obj->amount_ttc;
1239  }
1240  } else {
1241  dol_print_error($this->db);
1242  }
1243 
1244  $discount->amount_ht = $discount->amount_ttc = $total_payments + $total_creditnote_and_deposit - $this->invoice->total_ttc;
1245  $discount->amount_tva = 0;
1246  $discount->tva_tx = 0;
1247 
1248  $result = $discount->create(DolibarrApiAccess::$user);
1249  if ($result < 0) {
1250  $error++;
1251  }
1252  }
1253  if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE || $this->invoice->type == Facture::TYPE_DEPOSIT) {
1254  foreach ($amount_ht as $tva_tx => $xxx) {
1255  $discount->amount_ht = abs($amount_ht[$tva_tx]);
1256  $discount->amount_tva = abs($amount_tva[$tva_tx]);
1257  $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
1258  $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
1259  $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
1260  $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
1261  $discount->tva_tx = abs($tva_tx);
1262 
1263  $result = $discount->create(DolibarrApiAccess::$user);
1264  if ($result < 0) {
1265  $error++;
1266  break;
1267  }
1268  }
1269  }
1270 
1271  if (empty($error)) {
1272  if ($this->invoice->type != Facture::TYPE_DEPOSIT) {
1273  // Set the invoice as paid
1274  $result = $this->invoice->setPaid(DolibarrApiAccess::$user);
1275  if ($result >= 0) {
1276  $this->db->commit();
1277  } else {
1278  $this->db->rollback();
1279  throw new RestException(500, 'Could not set paid');
1280  }
1281  } else {
1282  $this->db->commit();
1283  }
1284  } else {
1285  $this->db->rollback();
1286  throw new RestException(500, 'Discount creation error');
1287  }
1288  }
1289 
1290  return $this->_cleanObjectDatas($this->invoice);
1291  }
1292 
1309  public function useDiscount($id, $discountid)
1310  {
1311  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1312  throw new RestException(403);
1313  }
1314  if (empty($id)) {
1315  throw new RestException(400, 'Invoice ID is mandatory');
1316  }
1317  if (empty($discountid)) {
1318  throw new RestException(400, 'Discount ID is mandatory');
1319  }
1320 
1321  if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1322  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1323  }
1324 
1325  $result = $this->invoice->fetch($id);
1326  if (!$result) {
1327  throw new RestException(404, 'Invoice not found');
1328  }
1329 
1330  $result = $this->invoice->insert_discount($discountid);
1331  if ($result < 0) {
1332  throw new RestException(405, $this->invoice->error);
1333  }
1334 
1335  return $result;
1336  }
1337 
1354  public function useCreditNote($id, $discountid)
1355  {
1356  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1357 
1358  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1359  throw new RestException(403);
1360  }
1361  if (empty($id)) {
1362  throw new RestException(400, 'Invoice ID is mandatory');
1363  }
1364  if (empty($discountid)) {
1365  throw new RestException(400, 'Credit ID is mandatory');
1366  }
1367 
1368  if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1369  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1370  }
1371  $discount = new DiscountAbsolute($this->db);
1372  $result = $discount->fetch($discountid);
1373  if (!$result) {
1374  throw new RestException(404, 'Credit not found');
1375  }
1376 
1377  $result = $discount->link_to_invoice(0, $id);
1378  if ($result < 0) {
1379  throw new RestException(405, $discount->error);
1380  }
1381 
1382  return $result;
1383  }
1384 
1398  public function getPayments($id)
1399  {
1400  if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1401  throw new RestException(403);
1402  }
1403  if (empty($id)) {
1404  throw new RestException(400, 'Invoice ID is mandatory');
1405  }
1406 
1407  if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1408  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1409  }
1410 
1411  $result = $this->invoice->fetch($id);
1412  if (!$result) {
1413  throw new RestException(404, 'Invoice not found');
1414  }
1415 
1416  $result = $this->invoice->getListOfPayments();
1417  if ($result < 0) {
1418  throw new RestException(405, $this->invoice->error);
1419  }
1420 
1421  return $result;
1422  }
1423 
1424 
1446  public function addPayment($id, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '')
1447  {
1448  require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
1449 
1450  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1451  throw new RestException(403);
1452  }
1453  if (empty($id)) {
1454  throw new RestException(400, 'Invoice ID is mandatory');
1455  }
1456 
1457  if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1458  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1459  }
1460 
1461  if (isModEnabled("bank")) {
1462  if (empty($accountid)) {
1463  throw new RestException(400, 'Account ID is mandatory');
1464  }
1465  }
1466 
1467  if (empty($paymentid)) {
1468  throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1469  }
1470 
1471 
1472  $result = $this->invoice->fetch($id);
1473  if (!$result) {
1474  throw new RestException(404, 'Invoice not found');
1475  }
1476 
1477  // Calculate amount to pay
1478  $totalpaid = $this->invoice->getSommePaiement();
1479  $totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
1480  $totaldeposits = $this->invoice->getSumDepositsUsed();
1481  $resteapayer = price2num($this->invoice->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1482 
1483  $this->db->begin();
1484 
1485  $amounts = array();
1486  $multicurrency_amounts = array();
1487 
1488  // Clean parameters amount if payment is for a credit note
1489  if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1490  $resteapayer = price2num($resteapayer, 'MT');
1491  $amounts[$id] = (float) price2num(-1 * (float) $resteapayer, 'MT');
1492  // Multicurrency
1493  $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1494  $multicurrency_amounts[$id] = (float) price2num(-1 * (float) $newvalue, 'MT');
1495  } else {
1496  $resteapayer = price2num($resteapayer, 'MT');
1497  $amounts[$id] = (float) $resteapayer;
1498  // Multicurrency
1499  $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
1500  $multicurrency_amounts[$id] = (float) $newvalue;
1501  }
1502 
1503  // Creation of payment line
1504  $paymentobj = new Paiement($this->db);
1505  $paymentobj->datepaye = dol_stringtotime($datepaye);
1506  $paymentobj->amounts = $amounts; // Array with all payments dispatching with invoice id
1507  $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1508  $paymentobj->paiementid = $paymentid;
1509  $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1510  $paymentobj->num_payment = $num_payment;
1511  $paymentobj->note_private = $comment;
1512 
1513  $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1514  if ($payment_id < 0) {
1515  $this->db->rollback();
1516  throw new RestException(400, 'Payment error : '.$paymentobj->error);
1517  }
1518 
1519  if (isModEnabled("bank")) {
1520  $label = '(CustomerInvoicePayment)';
1521 
1522  if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1523  throw new RestException(400, 'Emetteur is mandatory when payment code is '.$paymentobj->paiementcode);
1524  }
1525  if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1526  $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1527  }
1528  $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1529  if ($result < 0) {
1530  $this->db->rollback();
1531  throw new RestException(400, 'Add payment to bank error : '.$paymentobj->error);
1532  }
1533  }
1534 
1535  $this->db->commit();
1536 
1537  return $payment_id;
1538  }
1539 
1566  public function addPaymentDistributed($arrayofamounts, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '', $ref_ext = '', $accepthigherpayment = false)
1567  {
1568  require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
1569 
1570  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1571  throw new RestException(403);
1572  }
1573  foreach ($arrayofamounts as $id => $amount) {
1574  if (empty($id)) {
1575  throw new RestException(400, 'Invoice ID is mandatory. Fill the invoice id and amount into arrayofamounts parameter. For example: {"1": "99.99", "2": "10"}');
1576  }
1577  if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
1578  throw new RestException(403, 'Access not allowed on invoice ID '.$id.' for login '.DolibarrApiAccess::$user->login);
1579  }
1580  }
1581 
1582  if (isModEnabled("bank")) {
1583  if (empty($accountid)) {
1584  throw new RestException(400, 'Account ID is mandatory');
1585  }
1586  }
1587  if (empty($paymentid)) {
1588  throw new RestException(400, 'Payment ID or Payment Code is mandatory');
1589  }
1590 
1591  $this->db->begin();
1592 
1593  $amounts = array();
1594  $multicurrency_amounts = array();
1595 
1596  // Loop on each invoice to pay
1597  foreach ($arrayofamounts as $id => $amountarray) {
1598  $result = $this->invoice->fetch($id);
1599  if (!$result) {
1600  $this->db->rollback();
1601  throw new RestException(404, 'Invoice ID '.$id.' not found');
1602  }
1603 
1604  if (($amountarray["amount"] == "remain" || $amountarray["amount"] > 0) && ($amountarray["multicurrency_amount"] == "remain" || $amountarray["multicurrency_amount"] > 0)) {
1605  $this->db->rollback();
1606  throw new RestException(400, 'Payment in both currency '.$id.' ( amount: '.$amountarray["amount"].', multicurrency_amount: '.$amountarray["multicurrency_amount"].')');
1607  }
1608 
1609  $is_multicurrency = 0;
1610  $total_ttc = $this->invoice->total_ttc;
1611 
1612  if ($amountarray["multicurrency_amount"] > 0 || $amountarray["multicurrency_amount"] == "remain") {
1613  $is_multicurrency = 1;
1614  $total_ttc = $this->invoice->multicurrency_total_ttc;
1615  }
1616 
1617  // Calculate amount to pay
1618  $totalpaid = $this->invoice->getSommePaiement($is_multicurrency);
1619  $totalcreditnotes = $this->invoice->getSumCreditNotesUsed($is_multicurrency);
1620  $totaldeposits = $this->invoice->getSumDepositsUsed($is_multicurrency);
1621  $remainstopay = $amount = price2num($total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
1622 
1623  if (!$is_multicurrency && $amountarray["amount"] != 'remain') {
1624  $amount = price2num($amountarray["amount"], 'MT');
1625  }
1626 
1627  if ($is_multicurrency && $amountarray["multicurrency_amount"] != 'remain') {
1628  $amount = price2num($amountarray["multicurrency_amount"], 'MT');
1629  }
1630 
1631  if ($amount > $remainstopay && !$accepthigherpayment) {
1632  $this->db->rollback();
1633  throw new RestException(400, 'Payment amount on invoice ID '.$id.' ('.$amount.') is higher than remain to pay ('.$remainstopay.')');
1634  }
1635 
1636  if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1637  $amount = price2num(-1 * (float) $amount, 'MT');
1638  }
1639 
1640  if ($is_multicurrency) {
1641  $amounts[$id] = null;
1642  // Multicurrency
1643  $multicurrency_amounts[$id] = (float) $amount;
1644  } else {
1645  $amounts[$id] = (float) $amount;
1646  // Multicurrency
1647  $multicurrency_amounts[$id] = null;
1648  }
1649  }
1650 
1651  // Creation of payment line
1652  $paymentobj = new Paiement($this->db);
1653  $paymentobj->datepaye = $datepaye;
1654  $paymentobj->amounts = $amounts; // Array with all payments dispatching with invoice id
1655  $paymentobj->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
1656  $paymentobj->paiementid = $paymentid;
1657  $paymentobj->paiementcode = (string) dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
1658  $paymentobj->num_payment = $num_payment;
1659  $paymentobj->note_private = $comment;
1660  $paymentobj->ref_ext = $ref_ext;
1661  $payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
1662  if ($payment_id < 0) {
1663  $this->db->rollback();
1664  throw new RestException(400, 'Payment error : '.$paymentobj->error);
1665  }
1666  if (isModEnabled("bank")) {
1667  $label = '(CustomerInvoicePayment)';
1668  if ($paymentobj->paiementcode == 'CHQ' && empty($chqemetteur)) {
1669  throw new RestException(400, 'Emetteur is mandatory when payment code is '.$paymentobj->paiementcode);
1670  }
1671  if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
1672  $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
1673  }
1674  $result = $paymentobj->addPaymentToBank(DolibarrApiAccess::$user, 'payment', $label, $accountid, $chqemetteur, $chqbank);
1675  if ($result < 0) {
1676  $this->db->rollback();
1677  throw new RestException(400, 'Add payment to bank error : '.$paymentobj->error);
1678  }
1679  }
1680 
1681  $this->db->commit();
1682 
1683  return $payment_id;
1684  }
1685 
1700  public function putPayment($id, $num_payment = '')
1701  {
1702  require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
1703 
1704  if (!DolibarrApiAccess::$user->hasRight('facture', 'creer')) {
1705  throw new RestException(403);
1706  }
1707  if (empty($id)) {
1708  throw new RestException(400, 'Payment ID is mandatory');
1709  }
1710 
1711  $paymentobj = new Paiement($this->db);
1712  $result = $paymentobj->fetch($id);
1713 
1714  if (!$result) {
1715  throw new RestException(404, 'Payment not found');
1716  }
1717 
1718  if (!empty($num_payment)) {
1719  $result = $paymentobj->update_num($num_payment);
1720  if ($result < 0) {
1721  throw new RestException(500, 'Error when updating the payment num');
1722  }
1723  }
1724 
1725  return [
1726  'success' => [
1727  'code' => 200,
1728  'message' => 'Payment updated'
1729  ]
1730  ];
1731  }
1732 
1733  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1740  protected function _cleanObjectDatas($object)
1741  {
1742  // phpcs:enable
1743  $object = parent::_cleanObjectDatas($object);
1744 
1745  unset($object->note);
1746  unset($object->address);
1747  unset($object->barcode_type);
1748  unset($object->barcode_type_code);
1749  unset($object->barcode_type_label);
1750  unset($object->barcode_type_coder);
1751  unset($object->canvas);
1752 
1753  return $object;
1754  }
1755 
1764  private function _validate($data)
1765  {
1766  $invoice = array();
1767  foreach (Invoices::$FIELDS as $field) {
1768  if (!isset($data[$field])) {
1769  throw new RestException(400, "$field field missing");
1770  }
1771  $invoice[$field] = $data[$field];
1772  }
1773  return $invoice;
1774  }
1775 
1776 
1790  public function getTemplateInvoice($id, $contact_list = 1)
1791  {
1792  return $this->_fetchTemplateInvoice($id, '', '', $contact_list);
1793  }
1794 
1808  private function _fetchTemplateInvoice($id, $ref = '', $ref_ext = '', $contact_list = 1)
1809  {
1810  if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1811  throw new RestException(403);
1812  }
1813 
1814  $result = $this->template_invoice->fetch($id, $ref, $ref_ext);
1815  if (!$result) {
1816  throw new RestException(404, 'Template invoice not found');
1817  }
1818 
1819  if (!DolibarrApi::_checkAccessToResource('facturerec', $this->template_invoice->id)) {
1820  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1821  }
1822 
1823  // Add external contacts ids
1824  if ($contact_list > -1) {
1825  $tmparray = $this->template_invoice->liste_contact(-1, 'external', $contact_list);
1826  if (is_array($tmparray)) {
1827  $this->template_invoice->contacts_ids = $tmparray;
1828  }
1829  }
1830 
1831  $this->template_invoice->fetchObjectLinked();
1832  return $this->_cleanTemplateObjectDatas($this->template_invoice);
1833  }
1834 
1835 
1836  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1844  {
1845  // phpcs:enable
1846  $object = parent::_cleanObjectDatas($object);
1847 
1848  unset($object->note);
1849  unset($object->address);
1850  unset($object->barcode_type);
1851  unset($object->barcode_type_code);
1852  unset($object->barcode_type_label);
1853  unset($object->barcode_type_coder);
1854  unset($object->canvas);
1855 
1856  return $object;
1857  }
1858 }
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
Class to manage customers orders.
Class to manage contracts.
Class to manage absolute discounts.
Class for API REST v1.
Definition: api.class.php:30
_filterObjectProperties($object, $properties)
Filter properties that will be returned on object.
Definition: api.class.php:136
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid')
Check access by user to a given resource.
Definition: api.class.php:369
_checkValForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
Definition: api.class.php:82
Class to manage invoices.
const TYPE_REPLACEMENT
Replacement invoice.
const TYPE_STANDARD
Standard invoice.
const TYPE_SITUATION
Situation invoice.
const TYPE_DEPOSIT
Deposit invoice.
const TYPE_CREDIT_NOTE
Credit note invoice.
Class to manage invoice templates.
postContact($id, $contactid, $type)
Add a contact type of given invoice.
putPayment($id, $num_payment='')
Update a payment.
addContact($id, $fk_socpeople, $type_contact, $source, $notrigger=0)
Adds a contact to an invoice.
createInvoiceFromOrder($orderid)
Create an invoice using an existing order.
markAsCreditAvailable($id)
Create a discount (credit available) for a credit note or a deposit.
getDiscount($id)
Get discount from invoice.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $thirdparty_ids='', $status='', $sqlfilters='', $properties='')
List invoices.
__construct()
Constructor.
put($id, $request_data=null)
Update invoice.
validate($id, $force_number='', $idwarehouse=0, $notrigger=0)
Validate an invoice.
getByRefExt($ref_ext, $contact_list=1)
Get properties of an invoice object by ref_ext.
_fetch($id, $ref='', $ref_ext='', $contact_list=1)
Get properties of an invoice object.
getByRef($ref, $contact_list=1)
Get properties of an invoice object by ref.
getPayments($id)
Get list of payments of a given invoice.
_cleanObjectDatas($object)
Clean sensible object datas.
post($request_data=null)
Create invoice object.
useDiscount($id, $discountid)
Add a discount line into an invoice (as an invoice line) using an existing absolute discount.
settounpaid($id)
Sets an invoice as unpaid.
getTemplateInvoice($id, $contact_list=1)
Get properties of a template invoice object.
putLine($id, $lineid, $request_data=null)
Update a line to a given invoice.
getLines($id)
Get lines of an invoice.
useCreditNote($id, $discountid)
Add an available credit note discount to payments of an existing invoice.
createInvoiceFromContract($contractid)
Create an invoice using a contract.
addPaymentDistributed($arrayofamounts, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment='', $comment='', $chqemetteur='', $chqbank='', $ref_ext='', $accepthigherpayment=false)
Add a payment to pay partially or completely one or several invoices.
_cleanTemplateObjectDatas($object)
Clean sensible object datas.
deleteContact($id, $contactid, $type)
Delete a contact type of given invoice.
postLine($id, $request_data=null)
Add a line to a given invoice.
_fetchTemplateInvoice($id, $ref='', $ref_ext='', $contact_list=1)
Get properties of an invoice object.
_validate($data)
Validate fields before create or update object.
addPayment($id, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment='', $comment='', $chqemetteur='', $chqbank='')
Add payment line to a specific invoice with the remain to pay as amount.
settopaid($id, $close_code='', $close_note='')
Sets an invoice as paid.
settodraft($id, $idwarehouse=-1)
Sets an invoice as draft.
deleteLine($id, $lineid)
Deletes a line of a given invoice.
Class to manage payments of customer invoices.
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:744
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition: date.lib.php:426
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
isModEnabled($module)
Is Dolibarr module enabled.
getMarginInfos($pv_ht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $pa_ht)
Return an array with margins information of a line.
div float
Buy price without taxes.
Definition: style.css.php:959