dolibarr 23.0.3
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 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21use Luracast\Restler\RestException;
22
23require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
24
31class Orders extends DolibarrApi
32{
36 public static $FIELDS = array(
37 'socid',
38 'date'
39 );
40
44 public $commande;
45
49 public function __construct()
50 {
51 global $db;
52
53 $this->db = $db;
54 $this->commande = new Commande($this->db);
55 }
56
68 public function get($id, $contact_list = -1)
69 {
70 return $this->_fetch($id, '', '', $contact_list);
71 }
72
86 public function getByRef($ref, $contact_list = -1)
87 {
88 return $this->_fetch(0, $ref, '', $contact_list);
89 }
90
104 public function getByRefExt($ref_ext, $contact_list = -1)
105 {
106 return $this->_fetch(0, '', $ref_ext, $contact_list);
107 }
108
122 private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = -1)
123 {
124 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
125 throw new RestException(403);
126 }
127 if (empty($id) && empty($ref) && empty($ref_ext)) {
128 throw new RestException(400, 'No ID or Ref provided');
129 }
130 $result = $this->commande->fetch($id, $ref, $ref_ext);
131 if (!$result) {
132 throw new RestException(404, 'Order not found');
133 }
134
135 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
136 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
137 }
138
139 if ($contact_list > -1) {
140 // Add external contacts ids
141 $tmparray = $this->commande->liste_contact(-1, 'external', $contact_list);
142 if (is_array($tmparray)) {
143 $this->commande->contacts_ids = $tmparray;
144 }
145 $tmparray = $this->commande->liste_contact(-1, 'internal', $contact_list);
146 if (is_array($tmparray)) {
147 $this->commande->contacts_ids_internal = $tmparray;
148 }
149 }
150
151 $this->commande->fetchObjectLinked();
152
153 // Add online_payment_url, cf #20477
154 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
155 $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', $this->commande->ref);
156
157 return $this->_cleanObjectDatas($this->commande);
158 }
159
182 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $sqlfilterlines = '', $properties = '', $pagination_data = false, $loadlinkedobjects = 0)
183 {
184 global $hookmanager;
185
186 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
187 throw new RestException(403);
188 }
189
190 $obj_ret = array();
191
192 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
193 $socids = DolibarrApiAccess::$user->socid ?: $thirdparty_ids;
194
195 // If the internal user must only see his customers, force searching by him
196 $search_sale = 0;
197 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
198 $search_sale = DolibarrApiAccess::$user->id;
199 }
200
201 $sql = "SELECT t.rowid";
202 $sql .= " FROM ".MAIN_DB_PREFIX."commande AS t";
203 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe AS s ON (s.rowid = t.fk_soc)";
204 $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
205 $sql .= ' WHERE t.entity IN ('.getEntity('commande').')';
206 if ($socids) {
207 $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
208 }
209 // Search on sale representative
210 if ($search_sale && $search_sale != '-1') {
211 if ($search_sale == -2) {
212 $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
213 } elseif ($search_sale > 0) {
214 $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).")";
215 }
216 }
217 $parameters = array();
218 $hookmanager->executeHooks('printFieldListWhere', $parameters, $this->commande); // Note that $action and $object may have been modified by hook
219 $sql .= $hookmanager->resPrint;
220 // Add sql filters
221 if ($sqlfilters) {
222 $errormessage = '';
223 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
224 if ($errormessage) {
225 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
226 }
227 }
228 // Add sql filters for lines
229 if ($sqlfilterlines) {
230 $errormessage = '';
231 $sql .= " AND EXISTS (SELECT tl.rowid FROM ".MAIN_DB_PREFIX."commandedet AS tl WHERE tl.fk_commande = t.rowid";
232 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilterlines, $errormessage);
233 $sql .= ")";
234 if ($errormessage) {
235 throw new RestException(400, 'Error when validating parameter sqlfilterlines -> '.$errormessage);
236 }
237 }
238
239 //this query will return total orders with the filters given
240 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
241
242 $sql .= $this->db->order($sortfield, $sortorder);
243 if ($limit) {
244 if ($page < 0) {
245 $page = 0;
246 }
247 $offset = $limit * $page;
248
249 $sql .= $this->db->plimit($limit + 1, $offset);
250 }
251
252 dol_syslog("API Rest request");
253 $result = $this->db->query($sql);
254
255 if ($result) {
256 $num = $this->db->num_rows($result);
257 $min = min($num, ($limit <= 0 ? $num : $limit));
258 $i = 0;
259 while ($i < $min) {
260 $obj = $this->db->fetch_object($result);
261 $commande_static = new Commande($this->db);
262 if ($commande_static->fetch($obj->rowid) > 0) {
263 // Add external contacts ids
264 $tmparray = $commande_static->liste_contact(-1, 'external', 1);
265 if (is_array($tmparray)) {
266 $commande_static->contacts_ids = $tmparray;
267 }
268
269 if ($loadlinkedobjects) {
270 // retrieve linked objects
271 $commande_static->fetchObjectLinked();
272 }
273
274 // Add online_payment_url, cf #20477
275 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
276 $commande_static->online_payment_url = getOnlinePaymentUrl(0, 'order', $commande_static->ref);
277
278 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($commande_static), $properties);
279 }
280 $i++;
281 }
282 } else {
283 throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
284 }
285
286 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
287 if ($pagination_data) {
288 $totalsResult = $this->db->query($sqlTotals);
289 $total = $this->db->fetch_object($totalsResult)->total;
290
291 $tmp = $obj_ret;
292 $obj_ret = [];
293
294 $obj_ret['data'] = $tmp;
295 $obj_ret['pagination'] = [
296 'total' => (int) $total,
297 'page' => $page, //count starts from 0
298 'page_count' => ceil((int) $total / $limit),
299 'limit' => $limit
300 ];
301 }
302
303 return $obj_ret;
304 }
305
316 public function post($request_data = null)
317 {
318 global $conf;
319 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
320 throw new RestException(403, "Insufficiant rights");
321 }
322
323 // Check mandatory fields
324 $this->_validate($request_data);
325
326 // Check thirdparty validity
327 $socid = (int) $request_data['socid'];
328 $thirdpartytmp = new Societe($this->db);
329 $thirdparty_result = $thirdpartytmp->fetch($socid);
330 if ($thirdparty_result < 1) {
331 throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
332 }
333 if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
334 throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
335 }
336
337 foreach ($request_data as $field => $value) {
338 if ($field === 'caller') {
339 // 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
340 $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
341 continue;
342 }
343 if ($field == 'id') {
344 throw new RestException(400, 'Creating with id field is forbidden');
345 }
346 if ($field == 'entity' && ((int) $value) != ((int) $conf->entity)) {
347 throw new RestException(403, 'Creating with entity='.((int) $value).' MUST be the same entity='.((int) $conf->entity).' as your API user/key belongs to');
348 }
349
350 $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
351 }
352 /*if (isset($request_data["lines"])) {
353 $lines = array();
354 foreach ($request_data["lines"] as $line) {
355 array_push($lines, (object) $line);
356 }
357 $this->commande->lines = $lines;
358 }*/
359
360 if ($this->commande->create(DolibarrApiAccess::$user) < 0) {
361 throw new RestException(500, "Error creating order", array_merge(array($this->commande->error), $this->commande->errors));
362 }
363
364 return ((int) $this->commande->id);
365 }
366
378 public function getLines($id)
379 {
380 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
381 throw new RestException(403);
382 }
383
384 $result = $this->commande->fetch($id);
385 if (!$result) {
386 throw new RestException(404, 'Order not found');
387 }
388
389 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
390 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
391 }
392 $this->commande->getLinesArray();
393 $result = array();
394 foreach ($this->commande->lines as $line) {
395 array_push($result, $this->_cleanObjectDatas($line));
396 }
397 return $result;
398 }
399
411 public function getLine($id, $lineid, $properties = '')
412 {
413 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
414 throw new RestException(403);
415 }
416
417 $result = $this->commande->fetch($id);
418 if (!$result) {
419 throw new RestException(404, 'Order not found');
420 }
421
422 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
423 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
424 }
425
426 $this->commande->fetch_lines();
427 foreach ($this->commande->lines as $line) {
428 if ($line->id == $lineid) {
429 return $this->_filterObjectProperties($this->_cleanObjectDatas($line), $properties);
430 }
431 }
432 throw new RestException(404, 'Line not found');
433 }
434
447 public function postLine($id, $request_data = null)
448 {
449 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
450 throw new RestException(403);
451 }
452
453 $result = $this->commande->fetch($id);
454 if (!$result) {
455 throw new RestException(404, 'Order not found');
456 }
457
458 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
459 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
460 }
461
462 $request_data = (object) $request_data;
463
464 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
465 $request_data->label = sanitizeVal($request_data->label);
466
467 $updateRes = $this->commande->addline(
468 $request_data->desc,
469 $request_data->subprice,
470 $request_data->qty,
471 $request_data->tva_tx,
472 $request_data->localtax1_tx,
473 $request_data->localtax2_tx,
474 $request_data->fk_product,
475 $request_data->remise_percent,
476 $request_data->info_bits,
477 $request_data->fk_remise_except,
478 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
479 $request_data->subprice,
480 $request_data->date_start,
481 $request_data->date_end,
482 $request_data->product_type,
483 $request_data->rang,
484 $request_data->special_code,
485 $request_data->fk_parent_line,
486 $request_data->fk_fournprice,
487 $request_data->pa_ht,
488 $request_data->label,
489 $request_data->array_options,
490 $request_data->fk_unit,
491 $request_data->origin,
492 $request_data->origin_id,
493 $request_data->multicurrency_subprice,
494 $request_data->ref_ext
495 );
496
497 if ($updateRes > 0) {
498 return $updateRes;
499 } else {
500 throw new RestException(400, $this->commande->error);
501 }
502 }
503
516 public function putLine($id, $lineid, $request_data = null)
517 {
518 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
519 throw new RestException(403);
520 }
521
522 $result = $this->commande->fetch($id);
523 if (!$result) {
524 throw new RestException(404, 'Order not found');
525 }
526
527 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
528 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
529 }
530
531 $request_data = (object) $request_data;
532
533 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
534 $request_data->label = sanitizeVal($request_data->label);
535
536 $updateRes = $this->commande->updateline(
537 $lineid,
538 $request_data->desc,
539 $request_data->subprice,
540 $request_data->qty,
541 $request_data->remise_percent,
542 $request_data->tva_tx,
543 $request_data->localtax1_tx,
544 $request_data->localtax2_tx,
545 $request_data->price_base_type ? $request_data->price_base_type : 'HT',
546 $request_data->info_bits,
547 $request_data->date_start,
548 $request_data->date_end,
549 $request_data->product_type,
550 $request_data->fk_parent_line,
551 0,
552 $request_data->fk_fournprice,
553 $request_data->pa_ht,
554 $request_data->label,
555 $request_data->special_code,
556 $request_data->array_options,
557 $request_data->fk_unit,
558 $request_data->multicurrency_subprice,
559 0,
560 $request_data->ref_ext,
561 $request_data->rang
562 );
563
564 if ($updateRes > 0) {
565 $result = $this->get($id);
566 unset($result->line);
567 return $this->_cleanObjectDatas($result);
568 }
569 return false;
570 }
571
584 public function deleteLine($id, $lineid)
585 {
586 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
587 throw new RestException(403);
588 }
589
590 $result = $this->commande->fetch($id);
591 if (!$result) {
592 throw new RestException(404, 'Order not found');
593 }
594
595 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
596 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
597 }
598
599 $updateRes = $this->commande->deleteLine(DolibarrApiAccess::$user, $lineid, $id);
600 if ($updateRes > 0) {
601 return $this->get($id);
602 } else {
603 throw new RestException(405, $this->commande->error);
604 }
605 }
606
620 public function getContacts($id, $type = '')
621 {
622 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
623 throw new RestException(403);
624 }
625
626 $result = $this->commande->fetch($id);
627 if (!$result) {
628 throw new RestException(404, 'Order not found');
629 }
630
631 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
632 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
633 }
634
635 $contacts = $this->commande->liste_contact(-1, 'external', 0, $type);
636 $socpeoples = $this->commande->liste_contact(-1, 'internal', 0, $type);
637
638 $contacts = array_merge($contacts, $socpeoples);
639
640 return $contacts;
641 }
642
662 public function postContact($id, $contactid, $type, $source = "external", $notrigger = 0)
663 {
664 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
665 throw new RestException(403);
666 }
667
668 // test source
669 if (empty($source)) {
670 throw new RestException(400, 'Source can not be empty');
671 }
672 $sql_distinct_source = "SELECT DISTINCT source";
673 $sql_distinct_source .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
674 $sql_distinct_source .= " WHERE element LIKE 'commande'";
675 $sql_distinct_source .= " AND source is NOT NULL";
676 $sql_distinct_source .= " AND active != 0";
677 $source_result = $this->db->query($sql_distinct_source);
678 $source_array = array();
679
680 if ($source_result) {
681 $num = $this->db->num_rows($source_result);
682 $i = 0;
683 while ($i < $num) {
684 $obj = $this->db->fetch_object($source_result);
685 $source_kind = (string) $obj->source;
686 array_push($source_array, $source_kind);
687 dol_syslog("source_kind=".$source_kind);
688 $i++;
689 }
690 } else {
691 throw new RestException(503, 'Error when retrieving a list of order contact sources: '.$this->db->lasterror());
692 }
693 if (!in_array($source, (array) $source_array, true)) {
694 throw new RestException(400, 'Combo of Source='.$source.' and Type='.$type.' not found in dictionary with active order contact types');
695 }
696
697 // test type
698 if (empty($type)) {
699 throw new RestException(400, 'type can not be empty');
700 }
701 // variable called type here, but code in dictionary and database
702 $sql_distinct_type = "SELECT DISTINCT code";
703 $sql_distinct_type .= " FROM ".MAIN_DB_PREFIX."c_type_contact";
704 $sql_distinct_type .= " WHERE element LIKE 'commande'";
705 $sql_distinct_type .= " AND source='".$this->db->escape($source)."'";
706 $sql_distinct_type .= " AND code is NOT NULL";
707 $sql_distinct_type .= " AND active != 0";
708 $type_result = $this->db->query($sql_distinct_type);
709 $type_array = array();
710
711 if ($type_result) {
712 $num = $this->db->num_rows($type_result);
713 $i = 0;
714 while ($i < $num) {
715 $obj = $this->db->fetch_object($type_result);
716 // variable called type here, but code in dictionary and database
717 $type_kind = (string) $obj->code;
718 array_push($type_array, $type_kind);
719 dol_syslog("type_kind=".$type_kind);
720 $i++;
721 }
722 } else {
723 throw new RestException(503, 'Error when retrieving a list of order contact types: '.$this->db->lasterror());
724 }
725 if (!in_array($type, (array) $type_array, true)) {
726 throw new RestException(400, 'Combo of Type='.$type.' and Source='.$source.' not found in dictionary with active order contact types');
727 }
728
729 // tests done, let's get it
730 $result = $this->commande->fetch($id);
731 if (!$result) {
732 throw new RestException(404, 'Order not found');
733 }
734 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
735 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
736 }
737
738 $result = $this->commande->add_contact($contactid, $type, $source, $notrigger);
739
740 if ($result == 0) {
741 throw new RestException(400, 'Already exists: Contact='.$contactid.' is already linked to the order='.$id.' as source='.$source.' and type='.$type);
742 } elseif ($result == -1) {
743 throw new RestException(400, 'Wrong contact='.$contactid);
744 } elseif ($result == -2) {
745 throw new RestException(400, 'Wrong type='.$type);
746 } elseif ($result == -3) {
747 throw new RestException(400, 'Not allowed contacts');
748 } elseif ($result == -4) {
749 throw new RestException(400, 'ErrorCommercialNotAllowedForThirdparty');
750 } elseif ($result == -5) {
751 throw new RestException(400, 'Trigger failed');
752 } elseif ($result == -6) {
753 throw new RestException(400, 'DB_ERROR_RECORD_ALREADY_EXISTS');
754 } elseif ($result == -7) {
755 throw new RestException(400, 'Some other error');
756 }
757
758 return array(
759 'success' => array(
760 'code' => 200,
761 'message' => 'Contact='.$contactid.' linked to the order='.$id.' as '.$source.' '.$type
762 )
763 );
764 }
765
783 public function deleteContact($id, $contactid, $type)
784 {
785 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
786 throw new RestException(403);
787 }
788
789 $result = $this->commande->fetch($id);
790 if (!$result) {
791 throw new RestException(404, 'Order not found');
792 }
793
794 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
795 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
796 }
797
798 foreach (array('internal', 'external') as $source) {
799 $contacts = $this->commande->liste_contact(-1, $source);
800 foreach ($contacts as $contact) {
801 if ($contact['id'] == $contactid && $contact['code'] == $type) {
802 $result = $this->commande->delete_contact($contact['rowid']);
803
804 if (!$result) {
805 throw new RestException(500, 'Error when deleting the contact '.$contact['rowid']);
806 }
807 }
808 }
809 }
810
811 return array(
812 'success' => array(
813 'code' => 200,
814 'message' => 'Contact unlinked from order'
815 )
816 );
817 }
818
828 public function put($id, $request_data = null)
829 {
830 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
831 throw new RestException(403);
832 }
833 if ($id == 0) {
834 throw new RestException(400, 'No order with id=0 can exist');
835 }
836 $result = $this->commande->fetch($id);
837 if (!$result) {
838 throw new RestException(404, 'Order not found');
839 }
840
841 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
842 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
843 }
844 foreach ($request_data as $field => $value) {
845 if ($field == 'id') {
846 continue;
847 }
848 if ($field === 'caller') {
849 // 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
850 $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
851 continue;
852 }
853 if ($field == 'array_options' && is_array($value)) {
854 foreach ($value as $index => $val) {
855 $this->commande->array_options[$index] = $this->_checkValForAPI($field, $val, $this->commande);
856 }
857 continue;
858 }
859
860 $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
861 }
862
863 // Update availability
864 if (!empty($this->commande->availability_id)) {
865 if ($this->commande->availability($this->commande->availability_id) < 0) {
866 throw new RestException(400, 'Error while updating availability');
867 }
868 }
869
870 if ($this->commande->update(DolibarrApiAccess::$user) > 0) {
871 return $this->get($id);
872 } else {
873 throw new RestException(500, $this->commande->error);
874 }
875 }
876
885 public function delete($id)
886 {
887 if (!DolibarrApiAccess::$user->hasRight('commande', 'supprimer')) {
888 throw new RestException(403);
889 }
890 if ($id == 0) {
891 throw new RestException(400, 'No order with id=0 can exist');
892 }
893 $result = $this->commande->fetch($id);
894 if (!$result) {
895 throw new RestException(404, 'Order not found');
896 }
897
898 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
899 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
900 }
901
902 if ($this->commande->delete(DolibarrApiAccess::$user) <= 0) {
903 throw new RestException(500, 'Error when deleting order : '.$this->commande->error);
904 }
905
906 return array(
907 'success' => array(
908 'code' => 200,
909 'message' => 'Order deleted'
910 )
911 );
912 }
913
935 public function validate($id, $idwarehouse = 0, $notrigger = 0)
936 {
937 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
938 throw new RestException(403);
939 }
940 $result = $this->commande->fetch($id);
941 if (!$result) {
942 throw new RestException(404, 'Order not found');
943 }
944
945 $result = $this->commande->fetch_thirdparty(); // do not check result, as failure is not fatal (used only for mail notification substitutes)
946
947 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
948 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
949 }
950
951 $result = $this->commande->valid(DolibarrApiAccess::$user, $idwarehouse, $notrigger);
952 if ($result == 0) {
953 throw new RestException(304, 'Error nothing done. May be object is already validated');
954 }
955 if ($result < 0) {
956 throw new RestException(500, 'Error when validating Order: '.$this->commande->error);
957 }
958 $result = $this->commande->fetch($id);
959
960 $this->commande->fetchObjectLinked();
961
962 //fix #20477 : add online_payment_url
963 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
964 $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', $this->commande->ref);
965
966 return $this->_cleanObjectDatas($this->commande);
967 }
968
986 public function reopen($id)
987 {
988 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
989 throw new RestException(403);
990 }
991 if (empty($id)) {
992 throw new RestException(400, 'Order ID is mandatory');
993 }
994 $result = $this->commande->fetch($id);
995 if (!$result) {
996 throw new RestException(404, 'Order not found');
997 }
998
999 $result = $this->commande->set_reopen(DolibarrApiAccess::$user);
1000 if ($result < 0) {
1001 throw new RestException(405, $this->commande->error);
1002 } elseif ($result == 0) {
1003 throw new RestException(304);
1004 }
1005
1006 return $result;
1007 }
1008
1022 public function setinvoiced($id)
1023 {
1024 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1025 throw new RestException(403);
1026 }
1027 if (empty($id)) {
1028 throw new RestException(400, 'Order ID is mandatory');
1029 }
1030 $result = $this->commande->fetch($id);
1031 if (!$result) {
1032 throw new RestException(404, 'Order not found');
1033 }
1034
1035 $result = $this->commande->classifyBilled(DolibarrApiAccess::$user);
1036 if ($result < 0) {
1037 throw new RestException(400, $this->commande->error);
1038 }
1039
1040 $result = $this->commande->fetch($id);
1041 if (!$result) {
1042 throw new RestException(404, 'Order not found');
1043 }
1044
1045 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1046 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1047 }
1048
1049 $this->commande->fetchObjectLinked();
1050
1051 return $this->_cleanObjectDatas($this->commande);
1052 }
1053
1063 public function close($id, $notrigger = 0)
1064 {
1065 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1066 throw new RestException(403);
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->cloture(DolibarrApiAccess::$user, $notrigger);
1078 if ($result == 0) {
1079 throw new RestException(304, 'Error nothing done. May be object is already closed');
1080 }
1081 if ($result < 0) {
1082 throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
1083 }
1084
1085 $result = $this->commande->fetch($id);
1086 if (!$result) {
1087 throw new RestException(404, 'Order not found');
1088 }
1089
1090 // test already done
1091 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1092 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1093 // }
1094
1095 $this->commande->fetchObjectLinked();
1096
1097 return $this->_cleanObjectDatas($this->commande);
1098 }
1099
1109 public function settodraft($id, $idwarehouse = -1)
1110 {
1111 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1112 throw new RestException(403);
1113 }
1114 $result = $this->commande->fetch($id);
1115 if (!$result) {
1116 throw new RestException(404, 'Order not found');
1117 }
1118
1119 if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1120 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1121 }
1122
1123 $result = $this->commande->setDraft(DolibarrApiAccess::$user, $idwarehouse);
1124 if ($result == 0) {
1125 throw new RestException(304, 'Nothing done. May be object is already closed');
1126 }
1127 if ($result < 0) {
1128 throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
1129 }
1130
1131 $result = $this->commande->fetch($id);
1132 if (!$result) {
1133 throw new RestException(404, 'Order not found');
1134 }
1135
1136 // test already done
1137 // if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
1138 // throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
1139 // }
1140
1141 $this->commande->fetchObjectLinked();
1142
1143 return $this->_cleanObjectDatas($this->commande);
1144 }
1145
1146
1160 public function createOrderFromProposal($proposalid)
1161 {
1162 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
1163
1164 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
1165 throw new RestException(403);
1166 }
1167 if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1168 throw new RestException(403);
1169 }
1170 if (empty($proposalid)) {
1171 throw new RestException(400, 'Proposal ID is mandatory');
1172 }
1173
1174 $propal = new Propal($this->db);
1175 $result = $propal->fetch($proposalid);
1176 if (!$result) {
1177 throw new RestException(404, 'Proposal not found');
1178 }
1179
1180 $result = $this->commande->createFromProposal($propal, DolibarrApiAccess::$user);
1181 if ($result < 0) {
1182 throw new RestException(405, $this->commande->error);
1183 }
1184 $this->commande->fetchObjectLinked();
1185
1186 return $this->_cleanObjectDatas($this->commande);
1187 }
1188
1204 public function getOrderShipments($id)
1205 {
1206 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1207 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
1208 throw new RestException(403);
1209 }
1210 $obj_ret = array();
1211 $sql = "SELECT e.rowid";
1212 $sql .= " FROM ".MAIN_DB_PREFIX."expedition as e";
1213 $sql .= " JOIN ".MAIN_DB_PREFIX."expeditiondet as edet";
1214 $sql .= " ON e.rowid = edet.fk_expedition";
1215 $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cdet";
1216 $sql .= " ON edet.fk_elementdet = cdet.rowid";
1217 $sql .= " JOIN ".MAIN_DB_PREFIX."commande as c";
1218 $sql .= " ON cdet.fk_commande = c.rowid";
1219 $sql .= " WHERE c.rowid = ".((int) $id);
1220 $sql .= " GROUP BY e.rowid";
1221 $sql .= $this->db->order("e.rowid", "ASC");
1222
1223 dol_syslog("API Rest request");
1224 $result = $this->db->query($sql);
1225
1226 if ($result) {
1227 $i = 0;
1228 $num = $this->db->num_rows($result);
1229 if ($num <= 0) {
1230 throw new RestException(404, 'Shipments not found ');
1231 }
1232 //$min = min($num, ($limit <= 0 ? $num : $limit));
1233 $min = $num;
1234 while ($i < $min) {
1235 $obj = $this->db->fetch_object($result);
1236 $shipment_static = new Expedition($this->db);
1237 if ($shipment_static->fetch($obj->rowid)) {
1238 $obj_ret[] = $this->_cleanObjectDatas($shipment_static);
1239 }
1240 $i++;
1241 }
1242 } else {
1243 throw new RestException(500, 'Error when retrieve shipment list : '.$this->db->lasterror());
1244 }
1245 return $obj_ret;
1246 }
1247
1262 public function createOrderShipment($id, $warehouse_id)
1263 {
1264 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1265 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
1266 throw new RestException(403);
1267 }
1268 if ($warehouse_id <= 0) {
1269 throw new RestException(404, 'Warehouse not found');
1270 }
1271 $result = $this->commande->fetch($id);
1272 if (!$result) {
1273 throw new RestException(404, 'Order not found');
1274 }
1275 $shipment = new Expedition($this->db);
1276 $shipment->socid = $this->commande->socid;
1277 $shipment->origin_id = $this->commande->id;
1278 $shipment->origin = $this->commande->element;
1279 $result = $shipment->create(DolibarrApiAccess::$user);
1280 if ($result <= 0) {
1281 throw new RestException(500, 'Error on creating expedition :'.$this->db->lasterror());
1282 }
1283 foreach ($this->commande->lines as $line) {
1284 $result = $shipment->create_line($warehouse_id, $line->id, $line->qty);
1285 if ($result <= 0) {
1286 throw new RestException(500, 'Error on creating expedition lines:'.$this->db->lasterror());
1287 }
1288 }
1289 return $shipment->id;
1290 }
1291
1292 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1302 protected function _cleanObjectDatas($object)
1303 {
1304 // phpcs:enable
1305 $object = parent::_cleanObjectDatas($object);
1306
1307 unset($object->note);
1308 unset($object->address);
1309 unset($object->barcode_type);
1310 unset($object->barcode_type_code);
1311 unset($object->barcode_type_label);
1312 unset($object->barcode_type_coder);
1313
1314 return $object;
1315 }
1316
1324 private function _validate($data)
1325 {
1326 if ($data === null) {
1327 $data = array();
1328 }
1329 $commande = array();
1330 foreach (Orders::$FIELDS as $field) {
1331 if (!isset($data[$field])) {
1332 throw new RestException(400, $field." field missing");
1333 }
1334 $commande[$field] = $data[$field];
1335 }
1336 return $commande;
1337 }
1338}
$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:33
_filterObjectProperties($object, $properties)
Filter properties that will be returned on object.
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid')
Check access by user to a given resource.
_checkValForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
Definition api.class.php:98
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...)
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
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.