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 /*if (isset($request_data["lines"])) {
365 $lines = array();
366 foreach ($request_data["lines"] as $line) {
367 array_push($lines, (object) $line);
368 }
369 $this->commande->lines = $lines;
370 }*/
371
372 if ($this->commande->create(DolibarrApiAccess::$user) < 0) {
373 throw new RestException(500, "Error creating order", array_merge(array($this->commande->error), $this->commande->errors));
374 }
375
376 return ((int) $this->commande->id);
377 }
378
391 public function getLines($id)
392 {
393 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
394 throw new RestException(403);
395 }
396
397 $result = $this->commande->fetch($id);
398 if (!$result) {
399 throw new RestException(404, 'Order not found');
400 }
401
402 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
403 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
404 }
405 $this->commande->getLinesArray();
406 $result = array();
407 foreach ($this->commande->lines as $line) {
408 array_push($result, $this->_cleanObjectDatas($line));
409 }
410 return $result;
411 }
412
425 public function getLine($id, $lineid, $properties = '')
426 {
427 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
428 throw new RestException(403);
429 }
430
431 $result = $this->commande->fetch($id);
432 if (!$result) {
433 throw new RestException(404, 'Order not found');
434 }
435
436 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
437 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
438 }
439
440 $this->commande->fetch_lines();
441 foreach ($this->commande->lines as $line) {
442 if ($line->id == $lineid) {
443 return $this->_filterObjectProperties($this->_cleanObjectDatas($line), $properties);
444 }
445 }
446 throw new RestException(404, 'Line not found');
447 }
448
462 public function postLine($id, $request_data = null)
463 {
464 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
465 throw new RestException(403);
466 }
467
468 $result = $this->commande->fetch($id);
469 if (!$result) {
470 throw new RestException(404, 'Order not found');
471 }
472
473 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
474 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
475 }
476
477 $request_data = (object) $request_data;
478
479 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
480 $request_data->label = sanitizeVal($request_data->label);
481
482 $updateRes = $this->commande->addline(
483 $request_data->desc,
484 $request_data->subprice,
485 $request_data->qty,
486 $request_data->tva_tx,
487 $request_data->localtax1_tx,
488 $request_data->localtax2_tx,
489 $request_data->fk_product,
490 $request_data->remise_percent,
491 $request_data->info_bits,
492 $request_data->fk_remise_except,
493 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
494 $request_data->subprice,
495 $request_data->date_start,
496 $request_data->date_end,
497 $request_data->product_type,
498 $request_data->rang,
499 $request_data->special_code,
500 $request_data->fk_parent_line,
501 $request_data->fk_fournprice,
502 $request_data->pa_ht,
503 $request_data->label,
504 $request_data->array_options,
505 $request_data->fk_unit,
506 $request_data->origin,
507 $request_data->origin_id,
508 $request_data->multicurrency_subprice,
509 $request_data->ref_ext
510 );
511
512 if ($updateRes > 0) {
513 return $updateRes;
514 } else {
515 throw new RestException(400, $this->commande->error);
516 }
517 }
518
532 public function putLine($id, $lineid, $request_data = null)
533 {
534 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
535 throw new RestException(403);
536 }
537
538 $result = $this->commande->fetch($id);
539 if (!$result) {
540 throw new RestException(404, 'Order not found');
541 }
542
543 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
544 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
545 }
546
547 $request_data = (object) $request_data;
548
549 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
550 $request_data->label = sanitizeVal($request_data->label);
551
552 $updateRes = $this->commande->updateline(
553 $lineid,
554 $request_data->desc,
555 $request_data->subprice,
556 $request_data->qty,
557 $request_data->remise_percent,
558 $request_data->tva_tx,
559 $request_data->localtax1_tx,
560 $request_data->localtax2_tx,
561 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
562 $request_data->info_bits,
563 $request_data->date_start,
564 $request_data->date_end,
565 $request_data->product_type,
566 $request_data->fk_parent_line,
567 0,
568 $request_data->fk_fournprice,
569 $request_data->pa_ht,
570 $request_data->label,
571 $request_data->special_code,
572 $request_data->array_options,
573 $request_data->fk_unit,
574 $request_data->multicurrency_subprice,
575 0,
576 $request_data->ref_ext,
577 $request_data->rang
578 );
579
580 if ($updateRes > 0) {
581 $result = $this->get($id);
582 unset($result->line);
583 return $this->_cleanObjectDatas($result);
584 }
585 return false;
586 }
587
601 public function deleteLine($id, $lineid)
602 {
603 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
604 throw new RestException(403);
605 }
606
607 $result = $this->commande->fetch($id);
608 if (!$result) {
609 throw new RestException(404, 'Order not found');
610 }
611
612 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
613 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
614 }
615
616 $updateRes = $this->commande->deleteLine(DolibarrApiAccess::$user, $lineid, $id);
617 if ($updateRes > 0) {
618 return $this->get($id);
619 } else {
620 throw new RestException(405, $this->commande->error);
621 }
622 }
623
638 public function getContacts($id, $type = '')
639 {
640 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
641 throw new RestException(403);
642 }
643
644 $result = $this->commande->fetch($id);
645 if (!$result) {
646 throw new RestException(404, 'Order not found');
647 }
648
649 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
650 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
651 }
652
653 $contacts = $this->commande->liste_contact(-1, 'external', 0, $type);
654 $socpeoples = $this->commande->liste_contact(-1, 'internal', 0, $type);
655
656 $contacts = array_merge($contacts, $socpeoples);
657
658 return $contacts;
659 }
660
681 public function postContact($id, $contactid, $type, $source = "external", $notrigger = 0)
682 {
683 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
684 throw new RestException(403);
685 }
686
687 // test source
688 if (empty($source)) {
689 throw new RestException(400, 'Source can not be empty');
690 }
691 $sql_distinct_source = "SELECT DISTINCT source";
692 $sql_distinct_source .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
693 $sql_distinct_source .= " WHERE element LIKE 'commande'";
694 $sql_distinct_source .= " AND source is NOT NULL";
695 $sql_distinct_source .= " AND active != 0";
696 $source_result = $this->db->query($sql_distinct_source);
697 $source_array = array();
698
699 if ($source_result) {
700 $num = $this->db->num_rows($source_result);
701 $i = 0;
702 while ($i < $num) {
703 $obj = $this->db->fetch_object($source_result);
704 $source_kind = (string) $obj->source;
705 array_push($source_array, $source_kind);
706 dol_syslog("source_kind=".$source_kind);
707 $i++;
708 }
709 } else {
710 throw new RestException(503, 'Error when retrieving a list of order contact sources: '.$this->db->lasterror());
711 }
712 if (!in_array($source, (array) $source_array, true)) {
713 throw new RestException(400, 'Combo of Source='.$source.' and Type='.$type.' not found in dictionary with active order contact types');
714 }
715
716 // test type
717 if (empty($type)) {
718 throw new RestException(400, 'type can not be empty');
719 }
720 // variable called type here, but code in dictionary and database
721 $sql_distinct_type = "SELECT DISTINCT code";
722 $sql_distinct_type .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
723 $sql_distinct_type .= " WHERE element LIKE 'commande'";
724 $sql_distinct_type .= " AND source='".$this->db->escape($source)."'";
725 $sql_distinct_type .= " AND code is NOT NULL";
726 $sql_distinct_type .= " AND active != 0";
727 $type_result = $this->db->query($sql_distinct_type);
728 $type_array = array();
729
730 if ($type_result) {
731 $num = $this->db->num_rows($type_result);
732 $i = 0;
733 while ($i < $num) {
734 $obj = $this->db->fetch_object($type_result);
735 // variable called type here, but code in dictionary and database
736 $type_kind = (string) $obj->code;
737 array_push($type_array, $type_kind);
738 dol_syslog("type_kind=".$type_kind);
739 $i++;
740 }
741 } else {
742 throw new RestException(503, 'Error when retrieving a list of order contact types: '.$this->db->lasterror());
743 }
744 if (!in_array($type, (array) $type_array, true)) {
745 throw new RestException(400, 'Combo of Type='.$type.' and Source='.$source.' not found in dictionary with active order contact types');
746 }
747
748 // tests done, let's get it
749 $result = $this->commande->fetch($id);
750 if (!$result) {
751 throw new RestException(404, 'Order not found');
752 }
753 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
754 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
755 }
756
757 $result = $this->commande->add_contact($contactid, $type, $source, $notrigger);
758
759 if ($result == 0) {
760 throw new RestException(400, 'Already exists: Contact='.$contactid.' is already linked to the order='.$id.' as source='.$source.' and type='.$type);
761 } elseif ($result == -1) {
762 throw new RestException(400, 'Wrong contact='.$contactid);
763 } elseif ($result == -2) {
764 throw new RestException(400, 'Wrong type='.$type);
765 } elseif ($result == -3) {
766 throw new RestException(400, 'Not allowed contacts');
767 } elseif ($result == -4) {
768 throw new RestException(400, 'ErrorCommercialNotAllowedForThirdparty');
769 } elseif ($result == -5) {
770 throw new RestException(400, 'Trigger failed');
771 } elseif ($result == -6) {
772 throw new RestException(400, 'DB_ERROR_RECORD_ALREADY_EXISTS');
773 } elseif ($result == -7) {
774 throw new RestException(400, 'Some other error');
775 }
776
777 return array(
778 'success' => array(
779 'code' => 200,
780 'message' => 'Contact='.$contactid.' linked to the order='.$id.' as '.$source.' '.$type
781 )
782 );
783 }
784
803 public function deleteContact($id, $contactid, $type)
804 {
805 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
806 throw new RestException(403);
807 }
808
809 $result = $this->commande->fetch($id);
810 if (!$result) {
811 throw new RestException(404, 'Order not found');
812 }
813
814 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
815 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
816 }
817
818 foreach (array('internal', 'external') as $source) {
819 $contacts = $this->commande->liste_contact(-1, $source);
820 foreach ($contacts as $contact) {
821 if ($contact['id'] == $contactid && $contact['code'] == $type) {
822 $result = $this->commande->delete_contact($contact['rowid']);
823
824 if (!$result) {
825 throw new RestException(500, 'Error when deleting the contact '.$contact['rowid']);
826 }
827 }
828 }
829 }
830
831 return array(
832 'success' => array(
833 'code' => 200,
834 'message' => 'Contact unlinked from order'
835 )
836 );
837 }
838
849 public function put($id, $request_data = null)
850 {
851 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
852 throw new RestException(403);
853 }
854 if ($id == 0) {
855 throw new RestException(400, 'No order with id=0 can exist');
856 }
857 $result = $this->commande->fetch($id);
858 if (!$result) {
859 throw new RestException(404, 'Order not found');
860 }
861
862 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
863 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
864 }
865 foreach ($request_data as $field => $value) {
866 if ($field == 'id') {
867 continue;
868 }
869 if ($field === 'caller') {
870 // 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
871 $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
872 continue;
873 }
874 if ($field == 'array_options' && is_array($value)) {
875 foreach ($value as $index => $val) {
876 $this->commande->array_options[$index] = $this->_checkValExtrafieldsForAPI($index, $val, $this->commande);
877 }
878 continue;
879 }
880
881 $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
882 }
883
884 // Update availability
885 if (!empty($this->commande->availability_id)) {
886 if ($this->commande->availability($this->commande->availability_id) < 0) {
887 throw new RestException(400, 'Error while updating availability');
888 }
889 }
890
891 if ($this->commande->update(DolibarrApiAccess::$user) > 0) {
892 return $this->get($id);
893 } else {
894 throw new RestException(500, $this->commande->error);
895 }
896 }
897
907 public function delete($id)
908 {
909 if (!DolibarrApiAccess::$user->hasRight('commande', 'supprimer')) {
910 throw new RestException(403);
911 }
912 if ($id == 0) {
913 throw new RestException(400, 'No order with id=0 can exist');
914 }
915 $result = $this->commande->fetch($id);
916 if (!$result) {
917 throw new RestException(404, 'Order not found');
918 }
919
920 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
921 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
922 }
923
924 if ($this->commande->delete(DolibarrApiAccess::$user) <= 0) {
925 throw new RestException(500, 'Error when deleting order : '.$this->commande->error);
926 }
927
928 return array(
929 'success' => array(
930 'code' => 200,
931 'message' => 'Order deleted'
932 )
933 );
934 }
935
958 public function validate($id, $idwarehouse = 0, $notrigger = 0)
959 {
960 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
961 throw new RestException(403);
962 }
963 $result = $this->commande->fetch($id);
964 if (!$result) {
965 throw new RestException(404, 'Order not found');
966 }
967
968 $result = $this->commande->fetch_thirdparty(); // do not check result, as failure is not fatal (used only for mail notification substitutes)
969
970 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
971 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
972 }
973
974 $result = $this->commande->valid(DolibarrApiAccess::$user, $idwarehouse, $notrigger);
975 if ($result == 0) {
976 throw new RestException(304, 'Error nothing done. May be object is already validated');
977 }
978 if ($result < 0) {
979 throw new RestException(500, 'Error when validating Order: '.$this->commande->error);
980 }
981 $result = $this->commande->fetch($id);
982
983 $this->commande->fetchObjectLinked();
984
985 //fix #20477 : add online_payment_url
986 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
987 $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', (string) $this->commande->ref);
988
989 return $this->_cleanObjectDatas($this->commande);
990 }
991
1010 public function reopen($id)
1011 {
1012 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1013 throw new RestException(403);
1014 }
1015 if (empty($id)) {
1016 throw new RestException(400, 'Order ID is mandatory');
1017 }
1018 $result = $this->commande->fetch($id);
1019 if (!$result) {
1020 throw new RestException(404, 'Order not found');
1021 }
1022
1023 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1024 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1025 }
1026
1027 $result = $this->commande->set_reopen(DolibarrApiAccess::$user);
1028 if ($result < 0) {
1029 throw new RestException(405, $this->commande->error);
1030 } elseif ($result == 0) {
1031 throw new RestException(304);
1032 }
1033
1034 return $result;
1035 }
1036
1051 public function setinvoiced($id)
1052 {
1053 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1054 throw new RestException(403);
1055 }
1056 if (empty($id)) {
1057 throw new RestException(400, 'Order ID is mandatory');
1058 }
1059 $result = $this->commande->fetch($id);
1060 if (!$result) {
1061 throw new RestException(404, 'Order not found');
1062 }
1063
1064 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1065 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1066 }
1067
1068 $result = $this->commande->classifyBilled(DolibarrApiAccess::$user);
1069 if ($result < 0) {
1070 throw new RestException(400, $this->commande->error);
1071 }
1072
1073 $this->commande->fetchObjectLinked();
1074
1075 return $this->_cleanObjectDatas($this->commande);
1076 }
1077
1088 public function close($id, $notrigger = 0)
1089 {
1090 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1091 throw new RestException(403);
1092 }
1093 $result = $this->commande->fetch($id);
1094 if (!$result) {
1095 throw new RestException(404, 'Order not found');
1096 }
1097
1098 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1099 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1100 }
1101
1102 $result = $this->commande->cloture(DolibarrApiAccess::$user, $notrigger);
1103 if ($result == 0) {
1104 throw new RestException(304, 'Error nothing done. May be object is already closed');
1105 }
1106 if ($result < 0) {
1107 throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
1108 }
1109
1110 $result = $this->commande->fetch($id);
1111 if (!$result) {
1112 throw new RestException(404, 'Order not found');
1113 }
1114
1115 // test already done
1116 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1117 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1118 // }
1119
1120 $this->commande->fetchObjectLinked();
1121
1122 return $this->_cleanObjectDatas($this->commande);
1123 }
1124
1135 public function settodraft($id, $idwarehouse = -1)
1136 {
1137 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1138 throw new RestException(403);
1139 }
1140 $result = $this->commande->fetch($id);
1141 if (!$result) {
1142 throw new RestException(404, 'Order not found');
1143 }
1144
1145 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1146 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1147 }
1148
1149 $result = $this->commande->setDraft(DolibarrApiAccess::$user, $idwarehouse);
1150 if ($result == 0) {
1151 throw new RestException(304, 'Nothing done. May be object is already closed');
1152 }
1153 if ($result < 0) {
1154 throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
1155 }
1156
1157 $result = $this->commande->fetch($id);
1158 if (!$result) {
1159 throw new RestException(404, 'Order not found');
1160 }
1161
1162 // test already done
1163 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1164 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1165 // }
1166
1167 $this->commande->fetchObjectLinked();
1168
1169 return $this->_cleanObjectDatas($this->commande);
1170 }
1171
1172
1187 public function createOrderFromProposal($proposalid)
1188 {
1189 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
1190
1191 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
1192 throw new RestException(403);
1193 }
1194 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1195 throw new RestException(403);
1196 }
1197 if (empty($proposalid)) {
1198 throw new RestException(400, 'Proposal ID is mandatory');
1199 }
1200
1201 $propal = new Propal($this->db);
1202 $result = $propal->fetch($proposalid);
1203 if (!$result) {
1204 throw new RestException(404, 'Proposal not found');
1205 }
1206
1207 $result = $this->commande->createFromProposal($propal, DolibarrApiAccess::$user);
1208 if ($result < 0) {
1209 throw new RestException(405, $this->commande->error);
1210 }
1211 $this->commande->fetchObjectLinked();
1212
1213 return $this->_cleanObjectDatas($this->commande);
1214 }
1215
1232 public function getOrderShipments($id)
1233 {
1234 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1235 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
1236 throw new RestException(403);
1237 }
1238 $obj_ret = array();
1239 $sql = "SELECT e.rowid";
1240 $sql .= " FROM ".MAIN_DB_PREFIX."expedition as e";
1241 $sql .= " JOIN ".MAIN_DB_PREFIX."expeditiondet as edet";
1242 $sql .= " ON e.rowid = edet.fk_expedition";
1243 $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cdet";
1244 $sql .= " ON edet.fk_elementdet = cdet.rowid";
1245 $sql .= " JOIN ".MAIN_DB_PREFIX."commande as c";
1246 $sql .= " ON cdet.fk_commande = c.rowid";
1247 $sql .= " WHERE c.rowid = ".((int) $id);
1248 $sql .= " GROUP BY e.rowid";
1249 $sql .= $this->db->order("e.rowid", "ASC");
1250
1251 dol_syslog("API Rest request");
1252 $result = $this->db->query($sql);
1253
1254 if ($result) {
1255 $i = 0;
1256 $num = $this->db->num_rows($result);
1257 if ($num <= 0) {
1258 throw new RestException(404, 'Shipments not found ');
1259 }
1260 //$min = min($num, ($limit <= 0 ? $num : $limit));
1261 $min = $num;
1262 while ($i < $min) {
1263 $obj = $this->db->fetch_object($result);
1264 $shipment_static = new Expedition($this->db);
1265 if ($shipment_static->fetch($obj->rowid)) {
1266 $obj_ret[] = $this->_cleanObjectDatas($shipment_static);
1267 }
1268 $i++;
1269 }
1270 } else {
1271 throw new RestException(500, 'Error when retrieve shipment list : '.$this->db->lasterror());
1272 }
1273 return $obj_ret;
1274 }
1275
1291 public function createOrderShipment($id, $warehouse_id)
1292 {
1293 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1294 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
1295 throw new RestException(403);
1296 }
1297 if ($warehouse_id <= 0) {
1298 throw new RestException(404, 'Warehouse not found');
1299 }
1300 $result = $this->commande->fetch($id);
1301 if (!$result) {
1302 throw new RestException(404, 'Order not found');
1303 }
1304 $shipment = new Expedition($this->db);
1305 $shipment->socid = $this->commande->socid;
1306 $shipment->origin_id = $this->commande->id;
1307 $shipment->origin = $this->commande->element;
1308 $result = $shipment->create(DolibarrApiAccess::$user);
1309 if ($result <= 0) {
1310 throw new RestException(500, 'Error on creating expedition :'.$this->db->lasterror());
1311 }
1312 foreach ($this->commande->lines as $line) {
1313 $result = $shipment->create_line($warehouse_id, $line->id, $line->qty);
1314 if ($result <= 0) {
1315 throw new RestException(500, 'Error on creating expedition lines:'.$this->db->lasterror());
1316 }
1317 }
1318 return $shipment->id;
1319 }
1320
1321 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1331 protected function _cleanObjectDatas($object)
1332 {
1333 // phpcs:enable
1334 $object = parent::_cleanObjectDatas($object);
1335
1336 unset($object->note);
1337 unset($object->address);
1338 unset($object->barcode_type);
1339 unset($object->barcode_type_code);
1340 unset($object->barcode_type_label);
1341 unset($object->barcode_type_coder);
1342
1343 return $object;
1344 }
1345
1353 private function _validate($data)
1354 {
1355 if ($data === null) {
1356 $data = array();
1357 }
1358 $commande = array();
1359 foreach (Orders::$FIELDS as $field) {
1360 if (!isset($data[$field])) {
1361 throw new RestException(400, $field." field missing");
1362 }
1363 $commande[$field] = $data[$field];
1364 }
1365 return $commande;
1366 }
1367}
$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.
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