dolibarr 24.0.1
api_orders.class.php
1<?php
2/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
3 * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2025 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2025 William Mead <william@m34d.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
22use Luracast\Restler\RestException;
23
24require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
25
33class Orders extends DolibarrApi
34{
38 public static $FIELDS = array(
39 'socid',
40 'date'
41 );
42
46 public $commande;
47
51 public function __construct()
52 {
53 global $db;
54
55 $this->db = $db;
56 $this->commande = new Commande($this->db);
57 }
58
71 public function get($id, $contact_list = -1)
72 {
73 return $this->_fetch($id, '', '', $contact_list);
74 }
75
90 public function getByRef($ref, $contact_list = -1)
91 {
92 return $this->_fetch(0, $ref, '', $contact_list);
93 }
94
109 public function getByRefExt($ref_ext, $contact_list = -1)
110 {
111 return $this->_fetch(0, '', $ref_ext, $contact_list);
112 }
113
127 private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = -1)
128 {
129 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
130 throw new RestException(403);
131 }
132 if (empty($id) && empty($ref) && empty($ref_ext)) {
133 throw new RestException(400, 'No ID or Ref provided');
134 }
135 $result = $this->commande->fetch($id, $ref, $ref_ext);
136 if (!$result) {
137 throw new RestException(404, 'Order not found');
138 }
139
140 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
141 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
142 }
143
144 if ($contact_list > -1) {
145 // Add external contacts ids
146 $tmparray = $this->commande->liste_contact(-1, 'external', $contact_list);
147 if (is_array($tmparray)) {
148 $this->commande->contacts_ids = $tmparray;
149 }
150 $tmparray = $this->commande->liste_contact(-1, 'internal', $contact_list);
151 if (is_array($tmparray)) {
152 $this->commande->contacts_ids_internal = $tmparray;
153 }
154 }
155
156 $this->commande->fetchObjectLinked();
157
158 // Add online_payment_url, cf #20477
159 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
160 $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', (string) $this->commande->ref);
161
162 return $this->_cleanObjectDatas($this->commande);
163 }
164
189 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $sqlfilterlines = '', $properties = '', $pagination_data = false, $loadlinkedobjects = 0)
190 {
191 global $hookmanager;
192
193 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
194 throw new RestException(403);
195 }
196
197 $obj_ret = array();
198
199 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
200 $socids = DolibarrApiAccess::$user->socid ?: $thirdparty_ids;
201
202 // If the internal user must only see his customers, force searching by him
203 $search_sale = 0;
204 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
205 $search_sale = DolibarrApiAccess::$user->id;
206 }
207
208 $sql = "SELECT t.rowid";
209 $sql .= " FROM ".MAIN_DB_PREFIX."commande AS t";
210 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe AS s ON (s.rowid = t.fk_soc)";
211 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_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
212 $sql .= ' WHERE t.entity IN ('.getEntity('commande').')';
213 if ($socids) {
214 $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
215 }
216 // Search on sale representative
217 if ($search_sale && $search_sale != '-1') {
218 if ($search_sale == -2) {
219 $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
220 } elseif ($search_sale > 0) {
221 $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).")";
222 }
223 }
224 $parameters = array();
225 $hookmanager->executeHooks('printFieldListWhere', $parameters, $this->commande); // Note that $action and $object may have been modified by hook
226 $sql .= $hookmanager->resPrint;
227 // Add sql filters
228 if ($sqlfilters) {
229 $errormessage = '';
230 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
231 if ($errormessage) {
232 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
233 }
234 }
235 // Add sql filters for lines
236 if ($sqlfilterlines) {
237 $errormessage = '';
238 $sql .= " AND EXISTS (SELECT tl.rowid FROM ".MAIN_DB_PREFIX."commandedet AS tl WHERE tl.fk_commande = t.rowid";
239 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilterlines, $errormessage);
240 $sql .= ")";
241 if ($errormessage) {
242 throw new RestException(400, 'Error when validating parameter sqlfilterlines -> '.$errormessage);
243 }
244 }
245
246 //this query will return total orders with the filters given
247 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
248
249 $sql .= $this->db->order($sortfield, $sortorder);
250 if ($limit) {
251 if ($page < 0) {
252 $page = 0;
253 }
254 $offset = $limit * $page;
255
256 $sql .= $this->db->plimit($limit + 1, $offset);
257 }
258
259 dol_syslog("API Rest request");
260 $result = $this->db->query($sql);
261
262 if ($result) {
263 $num = $this->db->num_rows($result);
264 $min = min($num, ($limit <= 0 ? $num : $limit));
265 $i = 0;
266 while ($i < $min) {
267 $obj = $this->db->fetch_object($result);
268 $commande_static = new Commande($this->db);
269 if ($commande_static->fetch($obj->rowid) > 0) {
270 // Add external contacts ids
271 $tmparray = $commande_static->liste_contact(-1, 'external', 1);
272 if (is_array($tmparray)) {
273 $commande_static->contacts_ids = $tmparray;
274 }
275
276 if ($loadlinkedobjects) {
277 // retrieve linked objects
278 $commande_static->fetchObjectLinked();
279 }
280
281 // Add online_payment_url, cf #20477
282 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
283 $commande_static->online_payment_url = getOnlinePaymentUrl(0, 'order', (string) $commande_static->ref);
284
285 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($commande_static), $properties);
286 }
287 $i++;
288 }
289 } else {
290 throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
291 }
292
293 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
294 if ($pagination_data) {
295 $totalsResult = $this->db->query($sqlTotals);
296 $total = $this->db->fetch_object($totalsResult)->total;
297
298 $tmp = $obj_ret;
299 $obj_ret = [];
300
301 $obj_ret['data'] = $tmp;
302 $obj_ret['pagination'] = [
303 'total' => (int) $total,
304 'page' => $page, //count starts from 0
305 'page_count' => ceil((int) $total / $limit),
306 'limit' => $limit
307 ];
308 }
309
310 return $obj_ret;
311 }
312
327 public function post($request_data = null)
328 {
329 global $conf;
330 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
331 throw new RestException(403, "Insufficiant rights");
332 }
333
334 // Check mandatory fields
335 $this->_validate($request_data);
336
337 // Check thirdparty validity
338 $socid = (int) $request_data['socid'];
339 $thirdpartytmp = new Societe($this->db);
340 $thirdparty_result = $thirdpartytmp->fetch($socid);
341 if ($thirdparty_result < 1) {
342 throw new RestException(404, 'Third party with id='.$socid.' not found or not allowed');
343 }
344 if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
345 throw new RestException(404, 'Third party with id='.$thirdpartytmp->id.' not found or not allowed');
346 }
347
348 foreach ($request_data as $field => $value) {
349 if ($field === 'caller') {
350 // 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
351 $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
352 continue;
353 }
354 if ($field == 'id') {
355 throw new RestException(400, 'Creating with id field is forbidden');
356 }
357 if ($field == 'entity' && ((int) $value) != ((int) $conf->entity)) {
358 throw new RestException(403, 'Creating with entity='.((int) $value).' MUST be the same entity='.((int) $conf->entity).' as your API user/key belongs to');
359 }
360
361 $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
362 }
363 /*if (isset($request_data["lines"])) {
364 $lines = array();
365 foreach ($request_data["lines"] as $line) {
366 array_push($lines, (object) $line);
367 }
368 $this->commande->lines = $lines;
369 }*/
370
371 if ($this->commande->create(DolibarrApiAccess::$user) < 0) {
372 throw new RestException(500, "Error creating order", array_merge(array($this->commande->error), $this->commande->errors));
373 }
374
375 return ((int) $this->commande->id);
376 }
377
390 public function getLines($id)
391 {
392 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
393 throw new RestException(403);
394 }
395
396 $result = $this->commande->fetch($id);
397 if (!$result) {
398 throw new RestException(404, 'Order not found');
399 }
400
401 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
402 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
403 }
404 $this->commande->getLinesArray();
405 $result = array();
406 foreach ($this->commande->lines as $line) {
407 array_push($result, $this->_cleanObjectDatas($line));
408 }
409 return $result;
410 }
411
424 public function getLine($id, $lineid, $properties = '')
425 {
426 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
427 throw new RestException(403);
428 }
429
430 $result = $this->commande->fetch($id);
431 if (!$result) {
432 throw new RestException(404, 'Order not found');
433 }
434
435 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
436 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
437 }
438
439 $this->commande->fetch_lines();
440 foreach ($this->commande->lines as $line) {
441 if ($line->id == $lineid) {
442 return $this->_filterObjectProperties($this->_cleanObjectDatas($line), $properties);
443 }
444 }
445 throw new RestException(404, 'Line not found');
446 }
447
461 public function postLine($id, $request_data = null)
462 {
463 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
464 throw new RestException(403);
465 }
466
467 $result = $this->commande->fetch($id);
468 if (!$result) {
469 throw new RestException(404, 'Order not found');
470 }
471
472 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
473 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
474 }
475
476 $request_data = (object) $request_data;
477
478 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
479 $request_data->label = sanitizeVal($request_data->label);
480
481 $updateRes = $this->commande->addline(
482 $request_data->desc,
483 $request_data->subprice,
484 $request_data->qty,
485 $request_data->tva_tx,
486 $request_data->localtax1_tx,
487 $request_data->localtax2_tx,
488 $request_data->fk_product,
489 $request_data->remise_percent,
490 $request_data->info_bits,
491 $request_data->fk_remise_except,
492 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
493 $request_data->subprice,
494 $request_data->date_start,
495 $request_data->date_end,
496 $request_data->product_type,
497 $request_data->rang,
498 $request_data->special_code,
499 $request_data->fk_parent_line,
500 $request_data->fk_fournprice,
501 $request_data->pa_ht,
502 $request_data->label,
503 $request_data->array_options,
504 $request_data->fk_unit,
505 $request_data->origin,
506 $request_data->origin_id,
507 $request_data->multicurrency_subprice,
508 $request_data->ref_ext
509 );
510
511 if ($updateRes > 0) {
512 return $updateRes;
513 } else {
514 throw new RestException(400, $this->commande->error);
515 }
516 }
517
531 public function putLine($id, $lineid, $request_data = null)
532 {
533 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
534 throw new RestException(403);
535 }
536
537 $result = $this->commande->fetch($id);
538 if (!$result) {
539 throw new RestException(404, 'Order not found');
540 }
541
542 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
543 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
544 }
545
546 $request_data = (object) $request_data;
547
548 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
549 $request_data->label = sanitizeVal($request_data->label);
550
551 $orderline = new OrderLine($this->db);
552 $result = $orderline->fetch($lineid);
553 if (!$result) {
554 throw new RestException(404, 'Order line not found');
555 }
556
557 if ($orderline->fk_commande != $id) {
558 throw new RestException(403, 'Line does not belong to this order');
559 }
560
561 $updateRes = $this->commande->updateline(
562 $lineid,
563 $request_data->desc,
564 $request_data->subprice,
565 $request_data->qty,
566 $request_data->remise_percent,
567 $request_data->tva_tx,
568 $request_data->localtax1_tx,
569 $request_data->localtax2_tx,
570 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
571 $request_data->info_bits,
572 $request_data->date_start,
573 $request_data->date_end,
574 $request_data->product_type,
575 $request_data->fk_parent_line,
576 0,
577 $request_data->fk_fournprice,
578 $request_data->pa_ht,
579 $request_data->label,
580 $request_data->special_code,
581 $request_data->array_options,
582 $request_data->fk_unit,
583 $request_data->multicurrency_subprice,
584 0,
585 $request_data->ref_ext,
586 $request_data->rang
587 );
588
589 if ($updateRes > 0) {
590 $result = $this->get($id);
591 unset($result->line);
592 return $this->_cleanObjectDatas($result);
593 }
594 return false;
595 }
596
610 public function deleteLine($id, $lineid)
611 {
612 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
613 throw new RestException(403);
614 }
615
616 $result = $this->commande->fetch($id);
617 if (!$result) {
618 throw new RestException(404, 'Order not found');
619 }
620
621 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
622 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
623 }
624
625 $updateRes = $this->commande->deleteLine(DolibarrApiAccess::$user, $lineid, $id);
626 if ($updateRes > 0) {
627 return $this->get($id);
628 } else {
629 throw new RestException(405, $this->commande->error);
630 }
631 }
632
647 public function getContacts($id, $type = '')
648 {
649 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
650 throw new RestException(403);
651 }
652
653 $result = $this->commande->fetch($id);
654 if (!$result) {
655 throw new RestException(404, 'Order not found');
656 }
657
658 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
659 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
660 }
661
662 $contacts = $this->commande->liste_contact(-1, 'external', 0, $type);
663 $socpeoples = $this->commande->liste_contact(-1, 'internal', 0, $type);
664
665 $contacts = array_merge($contacts, $socpeoples);
666
667 return $contacts;
668 }
669
690 public function postContact($id, $contactid, $type, $source = "external", $notrigger = 0)
691 {
692 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
693 throw new RestException(403);
694 }
695
696 // test source
697 if (empty($source)) {
698 throw new RestException(400, 'Source can not be empty');
699 }
700 $sql_distinct_source = "SELECT DISTINCT source";
701 $sql_distinct_source .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
702 $sql_distinct_source .= " WHERE element LIKE 'commande'";
703 $sql_distinct_source .= " AND source is NOT NULL";
704 $sql_distinct_source .= " AND active != 0";
705 $source_result = $this->db->query($sql_distinct_source);
706 $source_array = array();
707
708 if ($source_result) {
709 $num = $this->db->num_rows($source_result);
710 $i = 0;
711 while ($i < $num) {
712 $obj = $this->db->fetch_object($source_result);
713 $source_kind = (string) $obj->source;
714 array_push($source_array, $source_kind);
715 dol_syslog("source_kind=".$source_kind);
716 $i++;
717 }
718 } else {
719 throw new RestException(503, 'Error when retrieving a list of order contact sources: '.$this->db->lasterror());
720 }
721 if (!in_array($source, (array) $source_array, true)) {
722 throw new RestException(400, 'Combo of Source='.$source.' and Type='.$type.' not found in dictionary with active order contact types');
723 }
724
725 // test type
726 if (empty($type)) {
727 throw new RestException(400, 'type can not be empty');
728 }
729 // variable called type here, but code in dictionary and database
730 $sql_distinct_type = "SELECT DISTINCT code";
731 $sql_distinct_type .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
732 $sql_distinct_type .= " WHERE element LIKE 'commande'";
733 $sql_distinct_type .= " AND source='".$this->db->escape($source)."'";
734 $sql_distinct_type .= " AND code is NOT NULL";
735 $sql_distinct_type .= " AND active != 0";
736 $type_result = $this->db->query($sql_distinct_type);
737 $type_array = array();
738
739 if ($type_result) {
740 $num = $this->db->num_rows($type_result);
741 $i = 0;
742 while ($i < $num) {
743 $obj = $this->db->fetch_object($type_result);
744 // variable called type here, but code in dictionary and database
745 $type_kind = (string) $obj->code;
746 array_push($type_array, $type_kind);
747 dol_syslog("type_kind=".$type_kind);
748 $i++;
749 }
750 } else {
751 throw new RestException(503, 'Error when retrieving a list of order contact types: '.$this->db->lasterror());
752 }
753 if (!in_array($type, (array) $type_array, true)) {
754 throw new RestException(400, 'Combo of Type='.$type.' and Source='.$source.' not found in dictionary with active order contact types');
755 }
756
757 // tests done, let's get it
758 $result = $this->commande->fetch($id);
759 if (!$result) {
760 throw new RestException(404, 'Order not found');
761 }
762 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
763 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
764 }
765
766 $result = $this->commande->add_contact($contactid, $type, $source, $notrigger);
767
768 if ($result == 0) {
769 throw new RestException(400, 'Already exists: Contact='.$contactid.' is already linked to the order='.$id.' as source='.$source.' and type='.$type);
770 } elseif ($result == -1) {
771 throw new RestException(400, 'Wrong contact='.$contactid);
772 } elseif ($result == -2) {
773 throw new RestException(400, 'Wrong type='.$type);
774 } elseif ($result == -3) {
775 throw new RestException(400, 'Not allowed contacts');
776 } elseif ($result == -4) {
777 throw new RestException(400, 'ErrorCommercialNotAllowedForThirdparty');
778 } elseif ($result == -5) {
779 throw new RestException(400, 'Trigger failed');
780 } elseif ($result == -6) {
781 throw new RestException(400, 'DB_ERROR_RECORD_ALREADY_EXISTS');
782 } elseif ($result == -7) {
783 throw new RestException(400, 'Some other error');
784 }
785
786 return array(
787 'success' => array(
788 'code' => 200,
789 'message' => 'Contact='.$contactid.' linked to the order='.$id.' as '.$source.' '.$type
790 )
791 );
792 }
793
812 public function deleteContact($id, $contactid, $type)
813 {
814 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
815 throw new RestException(403);
816 }
817
818 $result = $this->commande->fetch($id);
819 if (!$result) {
820 throw new RestException(404, 'Order not found');
821 }
822
823 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
824 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
825 }
826
827 foreach (array('internal', 'external') as $source) {
828 $contacts = $this->commande->liste_contact(-1, $source);
829 foreach ($contacts as $contact) {
830 if ($contact['id'] == $contactid && $contact['code'] == $type) {
831 $result = $this->commande->delete_contact($contact['rowid']);
832
833 if (!$result) {
834 throw new RestException(500, 'Error when deleting the contact '.$contact['rowid']);
835 }
836 }
837 }
838 }
839
840 return array(
841 'success' => array(
842 'code' => 200,
843 'message' => 'Contact unlinked from order'
844 )
845 );
846 }
847
858 public function put($id, $request_data = null)
859 {
860 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
861 throw new RestException(403);
862 }
863 if ($id == 0) {
864 throw new RestException(400, 'No order with id=0 can exist');
865 }
866 $result = $this->commande->fetch($id);
867 if (!$result) {
868 throw new RestException(404, 'Order not found');
869 }
870
871 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
872 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
873 }
874 foreach ($request_data as $field => $value) {
875 if ($field == 'id') {
876 continue;
877 }
878 if ($field === 'caller') {
879 // 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
880 $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
881 continue;
882 }
883 if ($field == 'array_options' && is_array($value)) {
884 foreach ($value as $index => $val) {
885 $this->commande->array_options[$index] = $this->_checkValExtrafieldsForAPI($index, $val, $this->commande);
886 }
887 continue;
888 }
889
890 $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
891 }
892
893 // Update availability
894 if (!empty($this->commande->availability_id)) {
895 if ($this->commande->availability($this->commande->availability_id) < 0) {
896 throw new RestException(400, 'Error while updating availability');
897 }
898 }
899
900 if ($this->commande->update(DolibarrApiAccess::$user) > 0) {
901 return $this->get($id);
902 } else {
903 throw new RestException(500, $this->commande->error);
904 }
905 }
906
916 public function delete($id)
917 {
918 if (!DolibarrApiAccess::$user->hasRight('commande', 'supprimer')) {
919 throw new RestException(403);
920 }
921 if ($id == 0) {
922 throw new RestException(400, 'No order with id=0 can exist');
923 }
924 $result = $this->commande->fetch($id);
925 if (!$result) {
926 throw new RestException(404, 'Order not found');
927 }
928
929 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
930 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
931 }
932
933 if ($this->commande->delete(DolibarrApiAccess::$user) <= 0) {
934 throw new RestException(500, 'Error when deleting order : '.$this->commande->error);
935 }
936
937 return array(
938 'success' => array(
939 'code' => 200,
940 'message' => 'Order deleted'
941 )
942 );
943 }
944
967 public function validate($id, $idwarehouse = 0, $notrigger = 0)
968 {
969 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
970 throw new RestException(403);
971 }
972 $result = $this->commande->fetch($id);
973 if (!$result) {
974 throw new RestException(404, 'Order not found');
975 }
976
977 $result = $this->commande->fetch_thirdparty(); // do not check result, as failure is not fatal (used only for mail notification substitutes)
978
979 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
980 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
981 }
982
983 $result = $this->commande->valid(DolibarrApiAccess::$user, $idwarehouse, $notrigger);
984 if ($result == 0) {
985 throw new RestException(304, 'Error nothing done. May be object is already validated');
986 }
987 if ($result < 0) {
988 throw new RestException(500, 'Error when validating Order: '.$this->commande->error);
989 }
990 $result = $this->commande->fetch($id);
991
992 $this->commande->fetchObjectLinked();
993
994 //fix #20477 : add online_payment_url
995 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
996 $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', (string) $this->commande->ref);
997
998 return $this->_cleanObjectDatas($this->commande);
999 }
1000
1019 public function reopen($id)
1020 {
1021 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1022 throw new RestException(403);
1023 }
1024 if (empty($id)) {
1025 throw new RestException(400, 'Order ID is mandatory');
1026 }
1027 $result = $this->commande->fetch($id);
1028 if (!$result) {
1029 throw new RestException(404, 'Order not found');
1030 }
1031
1032 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1033 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1034 }
1035
1036 $result = $this->commande->set_reopen(DolibarrApiAccess::$user);
1037 if ($result < 0) {
1038 throw new RestException(405, $this->commande->error);
1039 } elseif ($result == 0) {
1040 throw new RestException(304);
1041 }
1042
1043 return $result;
1044 }
1045
1060 public function setinvoiced($id)
1061 {
1062 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1063 throw new RestException(403);
1064 }
1065 if (empty($id)) {
1066 throw new RestException(400, 'Order ID is mandatory');
1067 }
1068 $result = $this->commande->fetch($id);
1069 if (!$result) {
1070 throw new RestException(404, 'Order not found');
1071 }
1072
1073 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1074 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1075 }
1076
1077 $result = $this->commande->classifyBilled(DolibarrApiAccess::$user);
1078 if ($result < 0) {
1079 throw new RestException(400, $this->commande->error);
1080 }
1081
1082 $this->commande->fetchObjectLinked();
1083
1084 return $this->_cleanObjectDatas($this->commande);
1085 }
1086
1097 public function close($id, $notrigger = 0)
1098 {
1099 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1100 throw new RestException(403);
1101 }
1102 $result = $this->commande->fetch($id);
1103 if (!$result) {
1104 throw new RestException(404, 'Order not found');
1105 }
1106
1107 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1108 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1109 }
1110
1111 $result = $this->commande->cloture(DolibarrApiAccess::$user, $notrigger);
1112 if ($result == 0) {
1113 throw new RestException(304, 'Error nothing done. May be object is already closed');
1114 }
1115 if ($result < 0) {
1116 throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
1117 }
1118
1119 $result = $this->commande->fetch($id);
1120 if (!$result) {
1121 throw new RestException(404, 'Order not found');
1122 }
1123
1124 // test already done
1125 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1126 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1127 // }
1128
1129 $this->commande->fetchObjectLinked();
1130
1131 return $this->_cleanObjectDatas($this->commande);
1132 }
1133
1144 public function settodraft($id, $idwarehouse = -1)
1145 {
1146 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1147 throw new RestException(403);
1148 }
1149 $result = $this->commande->fetch($id);
1150 if (!$result) {
1151 throw new RestException(404, 'Order not found');
1152 }
1153
1154 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1155 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1156 }
1157
1158 $result = $this->commande->setDraft(DolibarrApiAccess::$user, $idwarehouse);
1159 if ($result == 0) {
1160 throw new RestException(304, 'Nothing done. May be object is already closed');
1161 }
1162 if ($result < 0) {
1163 throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
1164 }
1165
1166 $result = $this->commande->fetch($id);
1167 if (!$result) {
1168 throw new RestException(404, 'Order not found');
1169 }
1170
1171 // test already done
1172 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1173 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1174 // }
1175
1176 $this->commande->fetchObjectLinked();
1177
1178 return $this->_cleanObjectDatas($this->commande);
1179 }
1180
1181
1196 public function createOrderFromProposal($proposalid)
1197 {
1198 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
1199
1200 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
1201 throw new RestException(403);
1202 }
1203 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1204 throw new RestException(403);
1205 }
1206 if (empty($proposalid)) {
1207 throw new RestException(400, 'Proposal ID is mandatory');
1208 }
1209
1210 $propal = new Propal($this->db);
1211 $result = $propal->fetch($proposalid);
1212 if (!$result) {
1213 throw new RestException(404, 'Proposal not found');
1214 }
1215
1216 if (!DolibarrApi::_checkAccessToResource('propal', $propal->id)) {
1217 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1218 }
1219
1220 $result = $this->commande->createFromProposal($propal, DolibarrApiAccess::$user);
1221 if ($result < 0) {
1222 throw new RestException(405, $this->commande->error);
1223 }
1224 $this->commande->fetchObjectLinked();
1225
1226 return $this->_cleanObjectDatas($this->commande);
1227 }
1228
1245 public function getOrderShipments($id)
1246 {
1247 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1248 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
1249 throw new RestException(403);
1250 }
1251 if (!DolibarrApi::_checkAccessToResource('commande', $id)) {
1252 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1253 }
1254 $obj_ret = array();
1255 $sql = "SELECT e.rowid";
1256 $sql .= " FROM ".MAIN_DB_PREFIX."expedition as e";
1257 $sql .= " JOIN ".MAIN_DB_PREFIX."expeditiondet as edet";
1258 $sql .= " ON e.rowid = edet.fk_expedition";
1259 $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cdet";
1260 $sql .= " ON edet.fk_elementdet = cdet.rowid";
1261 $sql .= " JOIN ".MAIN_DB_PREFIX."commande as c";
1262 $sql .= " ON cdet.fk_commande = c.rowid";
1263 $sql .= " WHERE c.rowid = ".((int) $id);
1264 $sql .= " GROUP BY e.rowid";
1265 $sql .= $this->db->order("e.rowid", "ASC");
1266
1267 dol_syslog("API Rest request");
1268 $result = $this->db->query($sql);
1269
1270 if ($result) {
1271 $i = 0;
1272 $num = $this->db->num_rows($result);
1273 if ($num <= 0) {
1274 throw new RestException(404, 'Shipments not found ');
1275 }
1276 //$min = min($num, ($limit <= 0 ? $num : $limit));
1277 $min = $num;
1278 while ($i < $min) {
1279 $obj = $this->db->fetch_object($result);
1280 $shipment_static = new Expedition($this->db);
1281 if ($shipment_static->fetch($obj->rowid)) {
1282 $obj_ret[] = $this->_cleanObjectDatas($shipment_static);
1283 }
1284 $i++;
1285 }
1286 } else {
1287 throw new RestException(500, 'Error when retrieve shipment list : '.$this->db->lasterror());
1288 }
1289 return $obj_ret;
1290 }
1291
1307 public function createOrderShipment($id, $warehouse_id)
1308 {
1309 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1310 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
1311 throw new RestException(403);
1312 }
1313 if ($warehouse_id <= 0) {
1314 throw new RestException(404, 'Warehouse not found');
1315 }
1316 $result = $this->commande->fetch($id);
1317 if (!$result) {
1318 throw new RestException(404, 'Order not found');
1319 }
1320 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1321 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1322 }
1323 $shipment = new Expedition($this->db);
1324 $shipment->socid = $this->commande->socid;
1325 $shipment->origin_id = $this->commande->id;
1326 $shipment->origin = $this->commande->element;
1327 $result = $shipment->create(DolibarrApiAccess::$user);
1328 if ($result <= 0) {
1329 throw new RestException(500, 'Error on creating expedition :'.$this->db->lasterror());
1330 }
1331 foreach ($this->commande->lines as $line) {
1332 $result = $shipment->create_line($warehouse_id, $line->id, $line->qty);
1333 if ($result <= 0) {
1334 throw new RestException(500, 'Error on creating expedition lines:'.$this->db->lasterror());
1335 }
1336 }
1337 return $shipment->id;
1338 }
1339
1340 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1350 protected function _cleanObjectDatas($object)
1351 {
1352 // phpcs:enable
1353 $object = parent::_cleanObjectDatas($object);
1354
1355 unset($object->note);
1356 unset($object->address);
1357 unset($object->barcode_type);
1358 unset($object->barcode_type_code);
1359 unset($object->barcode_type_label);
1360 unset($object->barcode_type_coder);
1361
1362 return $object;
1363 }
1364
1372 private function _validate($data)
1373 {
1374 if ($data === null) {
1375 $data = array();
1376 }
1377 $commande = array();
1378 foreach (Orders::$FIELDS as $field) {
1379 if (!isset($data[$field])) {
1380 throw new RestException(400, $field." field missing");
1381 }
1382 $commande[$field] = $data[$field];
1383 }
1384 return $commande;
1385 }
1386}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class to manage customers orders.
Class for API REST v1.
Definition api.class.php:35
_checkValExtrafieldsForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
_filterObjectProperties($object, $properties)
Filter properties that will be returned on object.
_checkValForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $parenttableforentity='')
Check access by user to a given resource.
Class to manage order lines.
deleteContact($id, $contactid, $type)
Unlink a contact type of given order.
__construct()
Constructor.
_validate($data)
Validate fields before create or update object.
deleteLine($id, $lineid)
Delete a line of a given order.
getByRef($ref, $contact_list=-1)
Get properties of an order object by ref.
close($id, $notrigger=0)
Close an order (Classify it as "Delivered")
postContact($id, $contactid, $type, $source="external", $notrigger=0)
Add a contact type of given order.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $thirdparty_ids='', $sqlfilters='', $sqlfilterlines='', $properties='', $pagination_data=false, $loadlinkedobjects=0)
List orders.
_cleanObjectDatas($object)
Clean sensible object datas @phpstan-template T.
_fetch($id, $ref='', $ref_ext='', $contact_list=-1)
Get properties of an order object.
put($id, $request_data=null)
Update order general fields (won't touch lines of order)
getLines($id)
Get lines of an order.
reopen($id)
Tag the order as validated (opened)
setinvoiced($id)
Classify the order as invoiced.
getContacts($id, $type='')
Get contacts of a given order.
getLine($id, $lineid, $properties='')
Get properties of a line of an order object by id.
postLine($id, $request_data=null)
Add a line to given order.
post($request_data=null)
Create a sale order.
validate($id, $idwarehouse=0, $notrigger=0)
Validate an order.
createOrderFromProposal($proposalid)
Create an order using an existing proposal.
putLine($id, $lineid, $request_data=null)
Update a line to given order.
getOrderShipments($id)
Get the shipments of an order.
settodraft($id, $idwarehouse=-1)
Set an order to draft.
createOrderShipment($id, $warehouse_id)
Create the shipment of an order.
getByRefExt($ref_ext, $contact_list=-1)
Get properties of an order object by ref_ext.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0, $forbiddenfields=array())
forgeSQLFromUniversalSearchCriteria
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php