dolibarr 25.0.0-alpha
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';
25require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
26
34class Orders extends DolibarrApi
35{
39 public static $FIELDS = array(
40 'socid',
41 'date'
42 );
43
47 public $commande;
48
52 public function __construct()
53 {
54 global $db;
55
56 $this->db = $db;
57 $this->commande = new Commande($this->db);
58 }
59
72 public function get($id, $contact_list = -1)
73 {
74 return $this->_fetch($id, '', '', $contact_list);
75 }
76
91 public function getByRef($ref, $contact_list = -1)
92 {
93 return $this->_fetch(0, $ref, '', $contact_list);
94 }
95
110 public function getByRefExt($ref_ext, $contact_list = -1)
111 {
112 return $this->_fetch(0, '', $ref_ext, $contact_list);
113 }
114
128 private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = -1)
129 {
130 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
131 throw new RestException(403);
132 }
133 if (empty($id) && empty($ref) && empty($ref_ext)) {
134 throw new RestException(400, 'No ID or Ref provided');
135 }
136 $result = $this->commande->fetch($id, $ref, $ref_ext);
137 if (!$result) {
138 throw new RestException(404, 'Order not found');
139 }
140
141 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
142 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
143 }
144
145 if ($contact_list > -1) {
146 // Add external contacts ids
147 $tmparray = $this->commande->liste_contact(-1, 'external', $contact_list);
148 if (is_array($tmparray)) {
149 $this->commande->contacts_ids = $tmparray;
150 }
151 $tmparray = $this->commande->liste_contact(-1, 'internal', $contact_list);
152 if (is_array($tmparray)) {
153 $this->commande->contacts_ids_internal = $tmparray;
154 }
155 }
156
157 $this->commande->fetchObjectLinked();
158
159 // Add online_payment_url, cf #20477
160 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
161 $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', (string) $this->commande->ref);
162
163 return $this->_cleanObjectDatas($this->commande);
164 }
165
190 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $sqlfilterlines = '', $properties = '', $pagination_data = false, $loadlinkedobjects = 0)
191 {
192 global $hookmanager;
193
194 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
195 throw new RestException(403);
196 }
197
198 $obj_ret = array();
199
200 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
201 $socids = DolibarrApiAccess::$user->socid ?: $thirdparty_ids;
202
203 // If the internal user must only see his customers, force searching by him
204 $search_sale = 0;
205 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
206 $search_sale = DolibarrApiAccess::$user->id;
207 }
208
209 $sql = "SELECT t.rowid";
210 $sql .= " FROM ".MAIN_DB_PREFIX."commande AS t";
211 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe AS s ON (s.rowid = t.fk_soc)";
212 $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
213 $sql .= ' WHERE t.entity IN ('.getEntity('commande').')';
214 if ($socids) {
215 $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
216 }
217 // Search on sale representative
218 if ($search_sale && $search_sale != '-1') {
219 if ($search_sale == -2) {
220 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', 0, 1);
221 } elseif ($search_sale > 0) {
222 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', (int) $search_sale);
223 }
224 }
225 $parameters = array();
226 $hookmanager->executeHooks('printFieldListWhere', $parameters, $this->commande); // Note that $action and $object may have been modified by hook
227 $sql .= $hookmanager->resPrint;
228 // Add sql filters
229 if ($sqlfilters) {
230 $errormessage = '';
231 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
232 if ($errormessage) {
233 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
234 }
235 }
236 // Add sql filters for lines
237 if ($sqlfilterlines) {
238 $errormessage = '';
239 $sql .= " AND EXISTS (SELECT tl.rowid FROM ".MAIN_DB_PREFIX."commandedet AS tl WHERE tl.fk_commande = t.rowid";
240 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilterlines, $errormessage);
241 $sql .= ")";
242 if ($errormessage) {
243 throw new RestException(400, 'Error when validating parameter sqlfilterlines -> '.$errormessage);
244 }
245 }
246
247 //this query will return total orders with the filters given
248 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
249
250 $sql .= $this->db->order($sortfield, $sortorder);
251 if ($limit) {
252 if ($page < 0) {
253 $page = 0;
254 }
255 $offset = $limit * $page;
256
257 $sql .= $this->db->plimit($limit + 1, $offset);
258 }
259
260 dol_syslog("API Rest request");
261 $result = $this->db->query($sql);
262
263 if ($result) {
264 $num = $this->db->num_rows($result);
265 $min = min($num, ($limit <= 0 ? $num : $limit));
266 $i = 0;
267 while ($i < $min) {
268 $obj = $this->db->fetch_object($result);
269 $commande_static = new Commande($this->db);
270 if ($commande_static->fetch($obj->rowid) > 0) {
271 // Add external contacts ids
272 $tmparray = $commande_static->liste_contact(-1, 'external', 1);
273 if (is_array($tmparray)) {
274 $commande_static->contacts_ids = $tmparray;
275 }
276
277 if ($loadlinkedobjects) {
278 // retrieve linked objects
279 $commande_static->fetchObjectLinked();
280 }
281
282 // Add online_payment_url, cf #20477
283 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
284 $commande_static->online_payment_url = getOnlinePaymentUrl(0, 'order', (string) $commande_static->ref);
285
286 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($commande_static), $properties);
287 }
288 $i++;
289 }
290 } else {
291 throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
292 }
293
294 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
295 if ($pagination_data) {
296 $totalsResult = $this->db->query($sqlTotals);
297 $total = $this->db->fetch_object($totalsResult)->total;
298
299 $tmp = $obj_ret;
300 $obj_ret = [];
301
302 $obj_ret['data'] = $tmp;
303 $obj_ret['pagination'] = [
304 'total' => (int) $total,
305 'page' => $page, //count starts from 0
306 'page_count' => ceil((int) $total / $limit),
307 'limit' => $limit
308 ];
309 }
310
311 return $obj_ret;
312 }
313
328 public function post($request_data = null)
329 {
330 global $conf;
331 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
332 throw new RestException(403, "Insufficiant rights");
333 }
334
335 // Check mandatory fields
336 $this->_validate($request_data);
337
338 // Check thirdparty validity
339 $socid = (int) $request_data['socid'];
340 $thirdpartytmp = new Societe($this->db);
341 $thirdparty_result = $thirdpartytmp->fetch($socid);
342 if ($thirdparty_result < 1) {
343 throw new RestException(404, 'Third party with id='.$socid.' not found or not allowed');
344 }
345 if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
346 throw new RestException(404, 'Third party with id='.$thirdpartytmp->id.' not found or not allowed');
347 }
348
349 foreach ($request_data as $field => $value) {
350 if ($field === 'caller') {
351 // 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
352 $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
353 continue;
354 }
355 if ($field == 'id') {
356 throw new RestException(400, 'Creating with id field is forbidden');
357 }
358 if ($field == 'entity' && ((int) $value) != ((int) $conf->entity)) {
359 throw new RestException(403, 'Creating with entity='.((int) $value).' MUST be the same entity='.((int) $conf->entity).' as your API user/key belongs to');
360 }
361
362 $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
363 }
364
365 if ($this->commande->create(DolibarrApiAccess::$user) < 0) {
366 throw new RestException(500, "Error creating order", array_merge(array($this->commande->error), $this->commande->errors));
367 }
368
369 return ((int) $this->commande->id);
370 }
371
384 public function getLines($id)
385 {
386 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
387 throw new RestException(403);
388 }
389
390 $result = $this->commande->fetch($id);
391 if (!$result) {
392 throw new RestException(404, 'Order not found');
393 }
394
395 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
396 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
397 }
398 $this->commande->getLinesArray();
399 $result = array();
400 foreach ($this->commande->lines as $line) {
401 array_push($result, $this->_cleanObjectDatas($line));
402 }
403 return $result;
404 }
405
418 public function getLine($id, $lineid, $properties = '')
419 {
420 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
421 throw new RestException(403);
422 }
423
424 $result = $this->commande->fetch($id);
425 if (!$result) {
426 throw new RestException(404, 'Order not found');
427 }
428
429 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
430 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
431 }
432
433 $this->commande->fetch_lines();
434 foreach ($this->commande->lines as $line) {
435 if ($line->id == $lineid) {
436 return $this->_filterObjectProperties($this->_cleanObjectDatas($line), $properties);
437 }
438 }
439 throw new RestException(404, 'Line not found');
440 }
441
455 public function postLine($id, $request_data = null)
456 {
457 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
458 throw new RestException(403);
459 }
460
461 $result = $this->commande->fetch($id);
462 if (!$result) {
463 throw new RestException(404, 'Order not found');
464 }
465
466 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
467 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
468 }
469
470 $request_data = (object) $request_data;
471
472 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
473 $request_data->label = sanitizeVal($request_data->label);
474
475 $updateRes = $this->commande->addline(
476 $request_data->desc,
477 $request_data->subprice,
478 $request_data->qty,
479 $request_data->tva_tx,
480 $request_data->localtax1_tx,
481 $request_data->localtax2_tx,
482 $request_data->fk_product,
483 $request_data->remise_percent,
484 $request_data->info_bits,
485 $request_data->fk_remise_except,
486 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
487 $request_data->subprice,
488 $request_data->date_start,
489 $request_data->date_end,
490 $request_data->product_type,
491 $request_data->rang,
492 $request_data->special_code,
493 $request_data->fk_parent_line,
494 $request_data->fk_fournprice,
495 $request_data->pa_ht,
496 $request_data->label,
497 $request_data->array_options,
498 $request_data->fk_unit,
499 $request_data->origin,
500 $request_data->origin_id,
501 $request_data->multicurrency_subprice,
502 $request_data->ref_ext
503 );
504
505 if ($updateRes > 0) {
506 return $updateRes;
507 } else {
508 throw new RestException(400, $this->commande->errorsToString());
509 }
510 }
511
525 public function putLine($id, $lineid, $request_data = null)
526 {
527 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
528 throw new RestException(403);
529 }
530
531 $result = $this->commande->fetch($id);
532 if (!$result) {
533 throw new RestException(404, 'Order not found');
534 }
535
536 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
537 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
538 }
539
540 $request_data = (object) $request_data;
541
542 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
543 $request_data->label = sanitizeVal($request_data->label);
544
545 $orderline = new OrderLine($this->db);
546 $result = $orderline->fetch($lineid);
547 if (!$result) {
548 throw new RestException(404, 'Order line not found');
549 }
550
551 if ($orderline->fk_commande != $id) {
552 throw new RestException(403, 'Line does not belong to this order');
553 }
554
555 $updateRes = $this->commande->updateline(
556 $lineid,
557 $request_data->desc,
558 $request_data->subprice,
559 $request_data->qty,
560 $request_data->remise_percent,
561 $request_data->tva_tx,
562 $request_data->localtax1_tx,
563 $request_data->localtax2_tx,
564 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
565 $request_data->info_bits,
566 $request_data->date_start,
567 $request_data->date_end,
568 $request_data->product_type,
569 $request_data->fk_parent_line,
570 0,
571 $request_data->fk_fournprice,
572 $request_data->pa_ht,
573 $request_data->label,
574 $request_data->special_code,
575 $request_data->array_options,
576 $request_data->fk_unit,
577 $request_data->multicurrency_subprice,
578 0,
579 $request_data->ref_ext,
580 $request_data->rang
581 );
582
583 if ($updateRes > 0) {
584 $result = $this->get($id);
585 unset($result->line);
586 return $this->_cleanObjectDatas($result);
587 }
588 return false;
589 }
590
604 public function deleteLine($id, $lineid)
605 {
606 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
607 throw new RestException(403);
608 }
609
610 $result = $this->commande->fetch($id);
611 if (!$result) {
612 throw new RestException(404, 'Order not found');
613 }
614
615 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
616 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
617 }
618
619 $updateRes = $this->commande->deleteLine(DolibarrApiAccess::$user, $lineid, $id);
620 if ($updateRes > 0) {
621 return $this->get($id);
622 } else {
623 throw new RestException(405, $this->commande->errorsToString());
624 }
625 }
626
641 public function getContacts($id, $type = '')
642 {
643 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
644 throw new RestException(403);
645 }
646
647 $result = $this->commande->fetch($id);
648 if (!$result) {
649 throw new RestException(404, 'Order not found');
650 }
651
652 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
653 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
654 }
655
656 $contacts = $this->commande->liste_contact(-1, 'external', 0, $type);
657 $socpeoples = $this->commande->liste_contact(-1, 'internal', 0, $type);
658
659 $contacts = array_merge($contacts, $socpeoples);
660
661 return $contacts;
662 }
663
684 public function postContact($id, $contactid, $type, $source = "external", $notrigger = 0)
685 {
686 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
687 throw new RestException(403);
688 }
689
690 // test source
691 if (empty($source)) {
692 throw new RestException(400, 'Source can not be empty');
693 }
694 $sql_distinct_source = "SELECT DISTINCT source";
695 $sql_distinct_source .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
696 $sql_distinct_source .= " WHERE element LIKE 'commande'";
697 $sql_distinct_source .= " AND source is NOT NULL";
698 $sql_distinct_source .= " AND active != 0";
699 $source_result = $this->db->query($sql_distinct_source);
700 $source_array = array();
701
702 if ($source_result) {
703 $num = $this->db->num_rows($source_result);
704 $i = 0;
705 while ($i < $num) {
706 $obj = $this->db->fetch_object($source_result);
707 $source_kind = (string) $obj->source;
708 array_push($source_array, $source_kind);
709 dol_syslog("source_kind=".$source_kind);
710 $i++;
711 }
712 } else {
713 throw new RestException(503, 'Error when retrieving a list of order contact sources: '.$this->db->lasterror());
714 }
715 if (!in_array($source, (array) $source_array, true)) {
716 throw new RestException(400, 'Combo of Source='.$source.' and Type='.$type.' not found in dictionary with active order contact types');
717 }
718
719 // test type
720 if (empty($type)) {
721 throw new RestException(400, 'type can not be empty');
722 }
723 // variable called type here, but code in dictionary and database
724 $sql_distinct_type = "SELECT DISTINCT code";
725 $sql_distinct_type .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
726 $sql_distinct_type .= " WHERE element LIKE 'commande'";
727 $sql_distinct_type .= " AND source='".$this->db->escape($source)."'";
728 $sql_distinct_type .= " AND code is NOT NULL";
729 $sql_distinct_type .= " AND active != 0";
730 $type_result = $this->db->query($sql_distinct_type);
731 $type_array = array();
732
733 if ($type_result) {
734 $num = $this->db->num_rows($type_result);
735 $i = 0;
736 while ($i < $num) {
737 $obj = $this->db->fetch_object($type_result);
738 // variable called type here, but code in dictionary and database
739 $type_kind = (string) $obj->code;
740 array_push($type_array, $type_kind);
741 dol_syslog("type_kind=".$type_kind);
742 $i++;
743 }
744 } else {
745 throw new RestException(503, 'Error when retrieving a list of order contact types: '.$this->db->lasterror());
746 }
747 if (!in_array($type, (array) $type_array, true)) {
748 throw new RestException(400, 'Combo of Type='.$type.' and Source='.$source.' not found in dictionary with active order contact types');
749 }
750
751 // tests done, let's get it
752 $result = $this->commande->fetch($id);
753 if (!$result) {
754 throw new RestException(404, 'Order not found');
755 }
756 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
757 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
758 }
759
760 $result = $this->commande->add_contact($contactid, $type, $source, $notrigger);
761
762 if ($result == 0) {
763 throw new RestException(400, 'Already exists: Contact='.$contactid.' is already linked to the order='.$id.' as source='.$source.' and type='.$type);
764 } elseif ($result == -1) {
765 throw new RestException(400, 'Wrong contact='.$contactid);
766 } elseif ($result == -2) {
767 throw new RestException(400, 'Wrong type='.$type);
768 } elseif ($result == -3) {
769 throw new RestException(400, 'Not allowed contacts');
770 } elseif ($result == -4) {
771 throw new RestException(400, 'ErrorCommercialNotAllowedForThirdparty');
772 } elseif ($result == -5) {
773 throw new RestException(400, 'Trigger failed');
774 } elseif ($result == -6) {
775 throw new RestException(400, 'DB_ERROR_RECORD_ALREADY_EXISTS');
776 } elseif ($result == -7) {
777 throw new RestException(400, 'Some other error');
778 }
779
780 return array(
781 'success' => array(
782 'code' => 200,
783 'message' => 'Contact='.$contactid.' linked to the order='.$id.' as '.$source.' '.$type
784 )
785 );
786 }
787
806 public function deleteContact($id, $contactid, $type)
807 {
808 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
809 throw new RestException(403);
810 }
811
812 $result = $this->commande->fetch($id);
813 if (!$result) {
814 throw new RestException(404, 'Order not found');
815 }
816
817 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
818 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
819 }
820
821 foreach (array('internal', 'external') as $source) {
822 $contacts = $this->commande->liste_contact(-1, $source);
823 foreach ($contacts as $contact) {
824 if ($contact['id'] == $contactid && $contact['code'] == $type) {
825 $result = $this->commande->delete_contact($contact['rowid']);
826
827 if (!$result) {
828 throw new RestException(500, 'Error when deleting the contact '.$contact['rowid']);
829 }
830 }
831 }
832 }
833
834 return array(
835 'success' => array(
836 'code' => 200,
837 'message' => 'Contact unlinked from order'
838 )
839 );
840 }
841
852 public function put($id, $request_data = null)
853 {
854 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
855 throw new RestException(403);
856 }
857 if ($id == 0) {
858 throw new RestException(400, 'No order with id=0 can exist');
859 }
860 $result = $this->commande->fetch($id);
861 if (!$result) {
862 throw new RestException(404, 'Order not found');
863 }
864
865 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
866 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
867 }
868 foreach ($request_data as $field => $value) {
869 if ($field == 'id') {
870 continue;
871 }
872 if ($field === 'caller') {
873 // 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
874 $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
875 continue;
876 }
877 if ($field == 'array_options' && is_array($value)) {
878 foreach ($value as $index => $val) {
879 $this->commande->array_options[$index] = $this->_checkValExtrafieldsForAPI($index, $val, $this->commande);
880 }
881 continue;
882 }
883
884 $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
885 }
886
887 // Update availability
888 if (!empty($this->commande->availability_id)) {
889 if ($this->commande->availability($this->commande->availability_id) < 0) {
890 throw new RestException(400, 'Error while updating availability');
891 }
892 }
893
894 if ($this->commande->update(DolibarrApiAccess::$user) > 0) {
895 return $this->get($id);
896 } else {
897 throw new RestException(500, $this->commande->errorsToString());
898 }
899 }
900
910 public function delete($id)
911 {
912 if (!DolibarrApiAccess::$user->hasRight('commande', 'supprimer')) {
913 throw new RestException(403);
914 }
915 if ($id == 0) {
916 throw new RestException(400, 'No order with id=0 can exist');
917 }
918 $result = $this->commande->fetch($id);
919 if (!$result) {
920 throw new RestException(404, 'Order not found');
921 }
922
923 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
924 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
925 }
926
927 if ($this->commande->delete(DolibarrApiAccess::$user) <= 0) {
928 throw new RestException(500, 'Error when deleting order : '.$this->commande->errorsToString());
929 }
930
931 return array(
932 'success' => array(
933 'code' => 200,
934 'message' => 'Order deleted'
935 )
936 );
937 }
938
961 public function validate($id, $idwarehouse = 0, $notrigger = 0)
962 {
963 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
964 throw new RestException(403);
965 }
966 $result = $this->commande->fetch($id);
967 if (!$result) {
968 throw new RestException(404, 'Order not found');
969 }
970
971 $result = $this->commande->fetch_thirdparty(); // do not check result, as failure is not fatal (used only for mail notification substitutes)
972
973 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
974 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
975 }
976
977 $result = $this->commande->valid(DolibarrApiAccess::$user, $idwarehouse, $notrigger);
978 if ($result == 0) {
979 throw new RestException(304, 'Error nothing done. May be object is already validated');
980 }
981 if ($result < 0) {
982 throw new RestException(500, 'Error when validating Order: '.$this->commande->errorsToString());
983 }
984 $result = $this->commande->fetch($id);
985
986 $this->commande->fetchObjectLinked();
987
988 //fix #20477 : add online_payment_url
989 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
990 $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', (string) $this->commande->ref);
991
992 return $this->_cleanObjectDatas($this->commande);
993 }
994
1013 public function reopen($id)
1014 {
1015 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1016 throw new RestException(403);
1017 }
1018 if (empty($id)) {
1019 throw new RestException(400, 'Order ID is mandatory');
1020 }
1021 $result = $this->commande->fetch($id);
1022 if (!$result) {
1023 throw new RestException(404, 'Order not found');
1024 }
1025
1026 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1027 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1028 }
1029
1030 $result = $this->commande->set_reopen(DolibarrApiAccess::$user);
1031 if ($result < 0) {
1032 throw new RestException(405, $this->commande->errorsToString());
1033 } elseif ($result == 0) {
1034 throw new RestException(304);
1035 }
1036
1037 return $result;
1038 }
1039
1054 public function setinvoiced($id)
1055 {
1056 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1057 throw new RestException(403);
1058 }
1059 if (empty($id)) {
1060 throw new RestException(400, 'Order ID is mandatory');
1061 }
1062 $result = $this->commande->fetch($id);
1063 if (!$result) {
1064 throw new RestException(404, 'Order not found');
1065 }
1066
1067 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1068 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1069 }
1070
1071 $result = $this->commande->classifyBilled(DolibarrApiAccess::$user);
1072 if ($result < 0) {
1073 throw new RestException(400, $this->commande->errorsToString());
1074 }
1075
1076 $this->commande->fetchObjectLinked();
1077
1078 return $this->_cleanObjectDatas($this->commande);
1079 }
1080
1091 public function close($id, $notrigger = 0)
1092 {
1093 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1094 throw new RestException(403);
1095 }
1096 $result = $this->commande->fetch($id);
1097 if (!$result) {
1098 throw new RestException(404, 'Order not found');
1099 }
1100
1101 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1102 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1103 }
1104
1105 $result = $this->commande->cloture(DolibarrApiAccess::$user, $notrigger);
1106 if ($result == 0) {
1107 throw new RestException(304, 'Error nothing done. May be object is already closed');
1108 }
1109 if ($result < 0) {
1110 throw new RestException(500, 'Error when closing Order: '.$this->commande->errorsToString());
1111 }
1112
1113 $result = $this->commande->fetch($id);
1114 if (!$result) {
1115 throw new RestException(404, 'Order not found');
1116 }
1117
1118 // test already done
1119 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1120 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1121 // }
1122
1123 $this->commande->fetchObjectLinked();
1124
1125 return $this->_cleanObjectDatas($this->commande);
1126 }
1127
1138 public function settodraft($id, $idwarehouse = -1)
1139 {
1140 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1141 throw new RestException(403);
1142 }
1143 $result = $this->commande->fetch($id);
1144 if (!$result) {
1145 throw new RestException(404, 'Order not found');
1146 }
1147
1148 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1149 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1150 }
1151
1152 $result = $this->commande->setDraft(DolibarrApiAccess::$user, $idwarehouse);
1153 if ($result == 0) {
1154 throw new RestException(304, 'Nothing done. May be object is already closed');
1155 }
1156 if ($result < 0) {
1157 throw new RestException(500, 'Error when closing Order: '.$this->commande->errorsToString());
1158 }
1159
1160 $result = $this->commande->fetch($id);
1161 if (!$result) {
1162 throw new RestException(404, 'Order not found');
1163 }
1164
1165 // test already done
1166 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1167 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1168 // }
1169
1170 $this->commande->fetchObjectLinked();
1171
1172 return $this->_cleanObjectDatas($this->commande);
1173 }
1174
1175
1190 public function createOrderFromProposal($proposalid)
1191 {
1192 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
1193
1194 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
1195 throw new RestException(403);
1196 }
1197 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1198 throw new RestException(403);
1199 }
1200 if (empty($proposalid)) {
1201 throw new RestException(400, 'Proposal ID is mandatory');
1202 }
1203
1204 $propal = new Propal($this->db);
1205 $result = $propal->fetch($proposalid);
1206 if (!$result) {
1207 throw new RestException(404, 'Proposal not found');
1208 }
1209
1210 if (!DolibarrApi::_checkAccessToResource('propal', $propal->id)) {
1211 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1212 }
1213
1214 $result = $this->commande->createFromProposal($propal, DolibarrApiAccess::$user);
1215 if ($result < 0) {
1216 throw new RestException(405, $this->commande->errorsToString());
1217 }
1218 $this->commande->fetchObjectLinked();
1219
1220 return $this->_cleanObjectDatas($this->commande);
1221 }
1222
1239 public function getOrderShipments($id)
1240 {
1241 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1242 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
1243 throw new RestException(403);
1244 }
1245 if (!DolibarrApi::_checkAccessToResource('commande', $id)) {
1246 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1247 }
1248 $obj_ret = array();
1249 $sql = "SELECT e.rowid";
1250 $sql .= " FROM ".MAIN_DB_PREFIX."expedition as e";
1251 $sql .= " JOIN ".MAIN_DB_PREFIX."expeditiondet as edet";
1252 $sql .= " ON e.rowid = edet.fk_expedition";
1253 $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cdet";
1254 $sql .= " ON edet.fk_elementdet = cdet.rowid";
1255 $sql .= " JOIN ".MAIN_DB_PREFIX."commande as c";
1256 $sql .= " ON cdet.fk_commande = c.rowid";
1257 $sql .= " WHERE c.rowid = ".((int) $id);
1258 $sql .= " GROUP BY e.rowid";
1259 $sql .= $this->db->order("e.rowid", "ASC");
1260
1261 dol_syslog("API Rest request");
1262 $result = $this->db->query($sql);
1263
1264 if ($result) {
1265 $i = 0;
1266 $num = $this->db->num_rows($result);
1267 if ($num <= 0) {
1268 throw new RestException(404, 'Shipments not found ');
1269 }
1270 //$min = min($num, ($limit <= 0 ? $num : $limit));
1271 $min = $num;
1272 while ($i < $min) {
1273 $obj = $this->db->fetch_object($result);
1274 $shipment_static = new Expedition($this->db);
1275 if ($shipment_static->fetch($obj->rowid)) {
1276 $obj_ret[] = $this->_cleanObjectDatas($shipment_static);
1277 }
1278 $i++;
1279 }
1280 } else {
1281 throw new RestException(500, 'Error when retrieve shipment list : '.$this->db->lasterror());
1282 }
1283 return $obj_ret;
1284 }
1285
1301 public function createOrderShipment($id, $warehouse_id)
1302 {
1303 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1304 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
1305 throw new RestException(403);
1306 }
1307 if ($warehouse_id <= 0) {
1308 throw new RestException(404, 'Warehouse not found');
1309 }
1310 $result = $this->commande->fetch($id);
1311 if (!$result) {
1312 throw new RestException(404, 'Order not found');
1313 }
1314 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1315 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1316 }
1317 $shipment = new Expedition($this->db);
1318 $shipment->socid = $this->commande->socid;
1319 $shipment->origin_id = $this->commande->id;
1320 $shipment->origin = $this->commande->element;
1321 $result = $shipment->create(DolibarrApiAccess::$user);
1322 if ($result <= 0) {
1323 throw new RestException(500, 'Error on creating expedition :'.$this->db->lasterror());
1324 }
1325 foreach ($this->commande->lines as $line) {
1326 $result = $shipment->create_line($warehouse_id, $line->id, $line->qty);
1327 if ($result <= 0) {
1328 throw new RestException(500, 'Error on creating expedition lines:'.$this->db->lasterror());
1329 }
1330 }
1331 return $shipment->id;
1332 }
1333
1334 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1344 protected function _cleanObjectDatas($object)
1345 {
1346 // phpcs:enable
1347 $object = parent::_cleanObjectDatas($object);
1348
1349 unset($object->note);
1350 unset($object->address);
1351 unset($object->barcode_type);
1352 unset($object->barcode_type_code);
1353 unset($object->barcode_type_label);
1354 unset($object->barcode_type_coder);
1355 unset($object->fk_remise_except);
1356 unset($object->line);
1357 unset($object->user);
1358 unset($object->country_id);
1359 unset($object->country_code);
1360 unset($object->state_id);
1361 unset($object->region_id);
1362 unset($object->name);
1363 unset($object->lastname);
1364 unset($object->firstname);
1365 unset($object->civility_id);
1366 unset($object->civility_code);
1367 unset($object->tms);
1368 unset($object->actiontypecode);
1369
1370 return $object;
1371 }
1372
1380 private function _validate($data)
1381 {
1382 if ($data === null) {
1383 $data = array();
1384 }
1385 $commande = array();
1386 foreach (Orders::$FIELDS as $field) {
1387 if (!isset($data[$field])) {
1388 throw new RestException(400, $field." field missing");
1389 }
1390 $commande[$field] = $data[$field];
1391 }
1392 return $commande;
1393 }
1394}
$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:
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.