dolibarr 25.0.0-alpha
api_receptions.class.php
1<?php
2/* Copyright (C) 2022 Quatadah Nasdami <quatadah.nasdami@gmail.com>
3 * Copyright (C) 2022 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2025 Frédéric France <frederic.france@free.fr>
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.'/reception/class/reception.class.php';
24require_once DOL_DOCUMENT_ROOT.'/reception/class/receptionlinebatch.class.php';
25require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
26
34{
38 public static $FIELDS = array(
39 'socid',
40 'origin_id',
41 'origin_type',
42 );
43
47 public $reception;
48
52 public function __construct()
53 {
54 global $db, $conf;
55 $this->db = $db;
56 $this->reception = new Reception($this->db);
57 }
58
68 public function get($id)
69 {
70 if (!DolibarrApiAccess::$user->hasRight('reception', 'lire')) {
71 throw new RestException(403);
72 }
73
74 $result = $this->reception->fetch($id);
75 if (!$result) {
76 throw new RestException(404, 'Reception not found');
77 }
78
79 if (!DolibarrApi::_checkAccessToResource('reception', $this->reception->id)) {
80 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
81 }
82
83 $this->reception->fetchObjectLinked();
84 return $this->_cleanObjectDatas($this->reception);
85 }
86
87
88
108 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $properties = '', $pagination_data = false)
109 {
110 if (!DolibarrApiAccess::$user->hasRight('reception', 'lire')) {
111 throw new RestException(403);
112 }
113
114 $obj_ret = array();
115
116 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
117 $socids = DolibarrApiAccess::$user->socid ?: $thirdparty_ids;
118
119 // If the internal user must only see his customers, force searching by him
120 $search_sale = 0;
121 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
122 $search_sale = DolibarrApiAccess::$user->id;
123 }
124
125 $sql = "SELECT t.rowid";
126 $sql .= " FROM ".MAIN_DB_PREFIX."reception AS t";
127 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."reception_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
128 if (preg_match("/el\.fk_source:=:\d+/", $sqlfilters)) {
129 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = t.rowid AND el.targettype = 'reception' AND el.sourcetype = 'order_supplier'";
130 }
131 $sql .= ' WHERE t.entity IN ('.getEntity('reception').')';
132 if ($socids) {
133 $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
134 }
135 // Search on sale representative
136 if ($search_sale && $search_sale != '-1') {
137 if ($search_sale == -2) {
138 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', 0, 1);
139 } elseif ($search_sale > 0) {
140 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', (int) $search_sale);
141 }
142 }
143 // Add sql filters
144 if ($sqlfilters) {
145 $errormessage = '';
146 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
147 if ($errormessage) {
148 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
149 }
150 }
151
152 //this query will return total receptions with the filters given
153 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
154
155 $sql .= $this->db->order($sortfield, $sortorder);
156 if ($limit) {
157 if ($page < 0) {
158 $page = 0;
159 }
160 $offset = $limit * $page;
161
162 $sql .= $this->db->plimit($limit + 1, $offset);
163 }
164
165 dol_syslog("API Rest request");
166 $result = $this->db->query($sql);
167
168 if ($result) {
169 $num = $this->db->num_rows($result);
170 $min = min($num, ($limit <= 0 ? $num : $limit));
171 $i = 0;
172 while ($i < $min) {
173 $obj = $this->db->fetch_object($result);
174 $reception_static = new Reception($this->db);
175 if ($reception_static->fetch($obj->rowid)) {
176 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($reception_static), $properties);
177 }
178 $i++;
179 }
180 } else {
181 throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
182 }
183
184 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
185 if ($pagination_data) {
186 $totalsResult = $this->db->query($sqlTotals);
187 $total = $this->db->fetch_object($totalsResult)->total;
188
189 $tmp = $obj_ret;
190 $obj_ret = [];
191
192 $obj_ret['data'] = $tmp;
193 $obj_ret['pagination'] = [
194 'total' => (int) $total,
195 'page' => $page, //count starts from 0
196 'page_count' => ceil((int) $total / $limit),
197 'limit' => $limit
198 ];
199 }
200
201 return $obj_ret;
202 }
203
212 public function post($request_data = null)
213 {
214 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
215 throw new RestException(403, "Insufficiant rights");
216 }
217 // Check mandatory fields
218 $result = $this->_validate($request_data);
219
220 foreach ($request_data as $field => $value) {
221 if ($field === 'caller') {
222 // 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
223 $this->reception->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
224 continue;
225 }
226
227 $this->reception->$field = $this->_checkValForAPI($field, $value, $this->reception);
228 }
229 if (isset($request_data["lines"]) && is_array($request_data['lines'])) {
230 $lines = array();
231 foreach ($request_data["lines"] as $line) {
232 $receptionline = new ReceptionLineBatch($this->db);
233
234 $receptionline->fk_product = $line['fk_product'];
235 $receptionline->fk_entrepot = $line['fk_entrepot'];
236 $receptionline->fk_element = $line['fk_element'] ?? $line['origin_id']; // example: purchase order id. this->origin is 'supplier_order'
237 $receptionline->origin_line_id = $line['fk_elementdet'] ?? $line['origin_line_id']; // example: purchase order id
238 $receptionline->fk_elementdet = $line['fk_elementdet'] ?? $line['origin_line_id']; // example: purchase order line id
239 $receptionline->origin_type = $line['element_type'] ?? $line['origin_type']; // example 'supplier_order'
240 $receptionline->element_type = $line['element_type'] ?? $line['origin_type']; // example 'supplier_order'
241 $receptionline->qty = $line['qty'];
242 //$receptionline->rang = $line['rang'];
243 $receptionline->array_options = $line['array_options'];
244 $receptionline->batch = $line['batch'];
245 $receptionline->eatby = $line['eatby'];
246 $receptionline->sellby = $line['sellby'];
247 $receptionline->cost_price = $line['cost_price'];
248 $receptionline->status = $line['status'];
249
250 $lines[] = $receptionline;
251 }
252 $this->reception->lines = $lines;
253 }
254
255 if ($this->reception->create(DolibarrApiAccess::$user) < 0) {
256 throw new RestException(500, "Error creating reception", array_merge(array($this->reception->error), $this->reception->errors));
257 }
258
259 return $this->reception->id;
260 }
261
262 // /**
263 // * Get lines of an reception
264 // *
265 // * @param int $id Id of reception
266 // *
267 // * @url GET {id}/lines
268 // *
269 // * @return int
270 // */
271 /*
272 public function getLines($id)
273 {
274 if (!DolibarrApiAccess::$user->hasRight('reception', 'lire')) {
275 throw new RestException(403);
276 }
277
278 $result = $this->reception->fetch($id);
279 if (! $result) {
280 throw new RestException(404, 'Reception not found');
281 }
282
283 if (!DolibarrApi::_checkAccessToResource('reception',$this->reception->id)) {
284 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
285 }
286 $this->reception->getLinesArray();
287 $result = array();
288 foreach ($this->reception->lines as $line) {
289 array_push($result,$this->_cleanObjectDatas($line));
290 }
291 return $result;
292 }
293 */
294
295 // /**
296 // * Add a line to given reception
297 // *
298 // * @param int $id Id of reception to update
299 // * @param array $request_data ShipmentLine data
300 // * @phan-param ?array<string,string> $request_data
301 // * @phpstan-param ?array<string,string> $request_data
302 // *
303 // * @url POST {id}/lines
304 // *
305 // * @return int
306 // */
307 /*
308 public function postLine($id, $request_data = null)
309 {
310 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
311 throw new RestException(403);
312 }
313
314 $result = $this->reception->fetch($id);
315 if (! $result) {
316 throw new RestException(404, 'Reception not found');
317 }
318
319 if (!DolibarrApi::_checkAccessToResource('reception',$this->reception->id)) {
320 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
321 }
322
323 $request_data = (object) $request_data;
324
325 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
326 $request_data->label = sanitizeVal($request_data->label);
327
328 $updateRes = $this->reception->addline(
329 $request_data->desc,
330 $request_data->subprice,
331 $request_data->qty,
332 $request_data->tva_tx,
333 $request_data->localtax1_tx,
334 $request_data->localtax2_tx,
335 $request_data->fk_product,
336 $request_data->remise_percent,
337 $request_data->info_bits,
338 $request_data->fk_remise_except,
339 'HT',
340 0,
341 $request_data->date_start,
342 $request_data->date_end,
343 $request_data->product_type,
344 $request_data->rang,
345 $request_data->special_code,
346 $fk_parent_line,
347 $request_data->fk_fournprice,
348 $request_data->pa_ht,
349 $request_data->label,
350 $request_data->array_options,
351 $request_data->fk_unit,
352 $request_data->origin,
353 $request_data->origin_id,
354 $request_data->multicurrency_subprice
355 );
356
357 if ($updateRes > 0) {
358 return $updateRes;
359
360 }
361 return false;
362 }*/
363
364 // /**
365 // * Update a line to given reception
366 // *
367 // * @param int $id Id of reception to update
368 // * @param int $lineid Id of line to update
369 // * @param array $request_data ShipmentLine data
370 // * @phan-param ?array<string,string> $request_data
371 // * @phpstan-param ?array<string,string> $request_data
372 // *
373 // * @url PUT {id}/lines/{lineid}
374 // *
375 // * @return object
376 // */
377 /*
378 public function putLine($id, $lineid, $request_data = null)
379 {
380 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
381 throw new RestException(403);
382 }
383
384 $result = $this->reception->fetch($id);
385 if (! $result) {
386 throw new RestException(404, 'Reception not found');
387 }
388
389 if (!DolibarrApi::_checkAccessToResource('reception',$this->reception->id)) {
390 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
391 }
392
393 $request_data = (object) $request_data;
394
395 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
396 $request_data->label = sanitizeVal($request_data->label);
397
398 $updateRes = $this->reception->updateline(
399 $lineid,
400 $request_data->desc,
401 $request_data->subprice,
402 $request_data->qty,
403 $request_data->remise_percent,
404 $request_data->tva_tx,
405 $request_data->localtax1_tx,
406 $request_data->localtax2_tx,
407 'HT',
408 $request_data->info_bits,
409 $request_data->date_start,
410 $request_data->date_end,
411 $request_data->product_type,
412 $request_data->fk_parent_line,
413 0,
414 $request_data->fk_fournprice,
415 $request_data->pa_ht,
416 $request_data->label,
417 $request_data->special_code,
418 $request_data->array_options,
419 $request_data->fk_unit,
420 $request_data->multicurrency_subprice
421 );
422
423 if ($updateRes > 0) {
424 $result = $this->get($id);
425 unset($result->line);
426 return $this->_cleanObjectDatas($result);
427 }
428 return false;
429 }*/
430
445 public function deleteLine($id, $lineid)
446 {
447 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
448 throw new RestException(403);
449 }
450
451 $result = $this->reception->fetch($id);
452 if (!$result) {
453 throw new RestException(404, 'Reception not found');
454 }
455
456 if (!DolibarrApi::_checkAccessToResource('reception', $this->reception->id)) {
457 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
458 }
459
460 // TODO Check the lineid $lineid is a line of object
461
462 $updateRes = $this->reception->deleteLine(DolibarrApiAccess::$user, $lineid);
463 if ($updateRes < 0) {
464 throw new RestException(405, $this->reception->error);
465 }
466
467 return array(
468 'success' => array(
469 'code' => 200,
470 'message' => 'Line deleted'
471 )
472 );
473 }
474
484 public function put($id, $request_data = null)
485 {
486 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
487 throw new RestException(403);
488 }
489
490 $result = $this->reception->fetch($id);
491 if (!$result) {
492 throw new RestException(404, 'Reception not found');
493 }
494
495 if (!DolibarrApi::_checkAccessToResource('reception', $this->reception->id)) {
496 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
497 }
498 foreach ($request_data as $field => $value) {
499 if ($field == 'id') {
500 continue;
501 }
502 if ($field === 'caller') {
503 // 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
504 $this->reception->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
505 continue;
506 }
507
508 if ($field == 'array_options' && is_array($value)) {
509 foreach ($value as $index => $val) {
510 $this->reception->array_options[$index] = $this->_checkValExtrafieldsForAPI($index, $val, $this->reception);
511 }
512 continue;
513 }
514
515 $this->reception->$field = $this->_checkValForAPI($field, $value, $this->reception);
516 }
517
518 if ($this->reception->update(DolibarrApiAccess::$user) > 0) {
519 return $this->get($id);
520 } else {
521 throw new RestException(500, $this->reception->error);
522 }
523 }
524
533 public function delete($id)
534 {
535 if (!DolibarrApiAccess::$user->hasRight('reception', 'supprimer')) {
536 throw new RestException(403);
537 }
538 $result = $this->reception->fetch($id);
539 if (!$result) {
540 throw new RestException(404, 'Reception not found');
541 }
542
543 if (!DolibarrApi::_checkAccessToResource('reception', $this->reception->id)) {
544 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
545 }
546
547 if (!$this->reception->delete(DolibarrApiAccess::$user)) {
548 throw new RestException(500, 'Error when deleting reception : '.$this->reception->error);
549 }
550
551 return array(
552 'success' => array(
553 'code' => 200,
554 'message' => 'Reception deleted'
555 )
556 );
557 }
558
578 public function validate($id, $notrigger = 0)
579 {
580 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
581 throw new RestException(403);
582 }
583 $result = $this->reception->fetch($id);
584 if (!$result) {
585 throw new RestException(404, 'Reception not found');
586 }
587
588 if (!DolibarrApi::_checkAccessToResource('reception', $this->reception->id)) {
589 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
590 }
591
592 $result = $this->reception->valid(DolibarrApiAccess::$user, $notrigger);
593 if ($result == 0) {
594 throw new RestException(304, 'Error nothing done. May be object is already validated');
595 }
596 if ($result < 0) {
597 throw new RestException(500, 'Error when validating Reception: '.$this->reception->error);
598 }
599
600 // Reload reception
601 $result = $this->reception->fetch($id);
602
603 $this->reception->fetchObjectLinked();
604 return $this->_cleanObjectDatas($this->reception);
605 }
606
607
608 // /**
609 // * Classify the reception as invoiced
610 // *
611 // * @param int $id Id of the reception
612 // *
613 // * @url POST {id}/setinvoiced
614 // *
615 // * @return int
616 // *
617 // * @throws RestException 400
618 // * @throws RestException 401
619 // * @throws RestException 404
620 // * @throws RestException 405
621 // */
622 /*
623 public function setinvoiced($id)
624 {
625
626 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
627 throw new RestException(403);
628 }
629 if (empty($id)) {
630 throw new RestException(400, 'Reception ID is mandatory');
631 }
632 $result = $this->reception->fetch($id);
633 if (!$result) {
634 throw new RestException(404, 'Reception not found');
635 }
636
637 $result = $this->reception->classifyBilled(DolibarrApiAccess::$user);
638 if ($result < 0) {
639 throw new RestException(400, $this->reception->error);
640 }
641 return $result;
642 }
643 */
644
645
646 // /**
647 // * Create a reception using an existing order.
648 // *
649 // * @param int $orderid Id of the order
650 // *
651 // * @url POST /createfromorder/{orderid}
652 // *
653 // * @return int
654 // * @throws RestException 400
655 // * @throws RestException 401
656 // * @throws RestException 404
657 // * @throws RestException 405
658 // */
659 /*
660 public function createShipmentFromOrder($orderid)
661 {
662
663 require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
664
665 if (!DolibarrApiAccess::$user->hasRight('reception', 'lire')) {
666 throw new RestException(403);
667 }
668 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
669 throw new RestException(403);
670 }
671 if (empty($proposalid)) {
672 throw new RestException(400, 'Order ID is mandatory');
673 }
674
675 $order = new Commande($this->db);
676 $result = $order->fetch($proposalid);
677 if (!$result) {
678 throw new RestException(404, 'Order not found');
679 }
680
681 $result = $this->reception->createFromOrder($order, DolibarrApiAccess::$user);
682 if( $result < 0) {
683 throw new RestException(405, $this->reception->error);
684 }
685 $this->reception->fetchObjectLinked();
686 return $this->_cleanObjectDatas($this->reception);
687 }
688 */
689
700 public function close($id, $notrigger = 0)
701 {
702 if (!DolibarrApiAccess::$user->hasRight('reception', 'creer')) {
703 throw new RestException(403);
704 }
705
706 $result = $this->reception->fetch($id);
707 if (!$result) {
708 throw new RestException(404, 'Reception not found');
709 }
710
711 if (!DolibarrApi::_checkAccessToResource('reception', $this->reception->id)) {
712 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
713 }
714
715 $result = $this->reception->setClosed();
716 if ($result == 0) {
717 throw new RestException(304, 'Error nothing done. May be object is already closed');
718 }
719 if ($result < 0) {
720 throw new RestException(500, 'Error when closing Reception: '.$this->reception->error);
721 }
722
723 // Reload reception
724 $result = $this->reception->fetch($id);
725
726 $this->reception->fetchObjectLinked();
727
728 return $this->_cleanObjectDatas($this->reception);
729 }
730
731 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
741 protected function _cleanObjectDatas($object)
742 {
743 // phpcs:enable
744 $object = parent::_cleanObjectDatas($object);
745
746 unset($object->thirdparty); // id already returned
747
748 unset($object->note);
749 unset($object->address);
750 unset($object->barcode_type);
751 unset($object->barcode_type_code);
752 unset($object->barcode_type_label);
753 unset($object->barcode_type_coder);
754
755 if (!empty($object->lines) && is_array($object->lines)) {
756 foreach ($object->lines as $line) {
757 unset($line->canvas);
758
759 unset($line->tva_tx);
760 unset($line->vat_src_code);
761 unset($line->total_ht);
762 unset($line->total_ttc);
763 unset($line->total_tva);
764 unset($line->total_localtax1);
765 unset($line->total_localtax2);
766 unset($line->remise_percent);
767 }
768 }
769
770 return $object;
771 }
772
780 private function _validate($data)
781 {
782 if ($data === null) {
783 $data = array();
784 }
785 $reception = array();
786 foreach (Receptions::$FIELDS as $field) {
787 if (!isset($data[$field])) {
788 throw new RestException(400, "$field field missing");
789 }
790 $reception[$field] = $data[$field];
791 }
792 return $reception;
793 }
794}
$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 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 receptions.
Class to manage table commandefournisseurdispatch.
close($id, $notrigger=0)
Classify the reception as invoiced.
validate($id, $notrigger=0)
Validate a reception.
post($request_data=null)
Create reception object.
deleteLine($id, $lineid)
Get lines of an reception.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $thirdparty_ids='', $sqlfilters='', $properties='', $pagination_data=false)
List receptions.
_cleanObjectDatas($object)
Clean sensible object datas @phpstan-template T.
__construct()
Constructor.
_validate($data)
Validate fields before create or update object.
put($id, $request_data=null)
Update reception general fields (won't touch lines of reception)
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.