dolibarr 25.0.0-alpha
api_shipments.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) 2025 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2025 Charlene Benke <charlene@patas-monkey.com>
6 * Copyright (C) 2025 Frédéric France <frederic.france@free.fr>
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.'/expedition/class/expedition.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 $shipment;
48
52 public function __construct()
53 {
54 global $db;
55 $this->db = $db;
56 $this->shipment = new Expedition($this->db);
57 }
58
69 public function get($id)
70 {
71 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
72 throw new RestException(403);
73 }
74
75 $result = $this->shipment->fetch($id);
76 if (!$result) {
77 throw new RestException(404, 'Shipment not found');
78 }
79
80 if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
81 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
82 }
83
84 $this->shipment->fetchObjectLinked();
85 return $this->_cleanObjectDatas($this->shipment);
86 }
87
88
89
109 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $properties = '', $pagination_data = false)
110 {
111 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
112 throw new RestException(403);
113 }
114
115 global $hookmanager;
116
117 $obj_ret = array();
118
119 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
120 $socids = DolibarrApiAccess::$user->socid ?: $thirdparty_ids;
121
122 // If the internal user must only see his customers, force searching by him
123 $search_sale = 0;
124 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
125 $search_sale = DolibarrApiAccess::$user->id;
126 }
127
128 $sql = "SELECT t.rowid";
129 $sql .= " FROM ".MAIN_DB_PREFIX."expedition AS t";
130 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe AS s ON (s.rowid = t.fk_soc)";
131 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expedition_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
132 $sql .= ' WHERE t.entity IN ('.getEntity('expedition').')';
133 if ($socids) {
134 $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
135 }
136 // Search on sale representative
137 if ($search_sale && $search_sale != '-1') {
138 if ($search_sale == -2) {
139 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', 0, 1);
140 } elseif ($search_sale > 0) {
141 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', (int) $search_sale);
142 }
143 }
144 // Add sql filters
145 if ($sqlfilters) {
146 $parameters = array('sqlfilters' => $sqlfilters, 'apiroute' => 'shipments', 'apimethod' => 'index');
147 $object = new stdClass();
148 $action = 'list';
149 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
150 if ($reshook > 0) {
151 $sql = $hookmanager->resPrint;
152 } elseif ($reshook == 0) {
153 $sql .= $hookmanager->resPrint;
154 }
155 $errormessage = '';
156 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
157 if ($errormessage) {
158 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
159 }
160 }
161
162 //this query will return total shipments with the filters given
163 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
164
165 $sql .= $this->db->order($sortfield, $sortorder);
166 if ($limit) {
167 if ($page < 0) {
168 $page = 0;
169 }
170 $offset = $limit * $page;
171
172 $sql .= $this->db->plimit($limit + 1, $offset);
173 }
174
175 dol_syslog("API Rest request");
176 $result = $this->db->query($sql);
177
178 if ($result) {
179 $num = $this->db->num_rows($result);
180 $min = min($num, ($limit <= 0 ? $num : $limit));
181 $i = 0;
182 while ($i < $min) {
183 $obj = $this->db->fetch_object($result);
184 $shipment_static = new Expedition($this->db);
185 if ($shipment_static->fetch($obj->rowid)) {
186 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($shipment_static), $properties);
187 }
188 $i++;
189 }
190 } else {
191 throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
192 }
193
194 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
195 if ($pagination_data) {
196 $totalsResult = $this->db->query($sqlTotals);
197 $total = $this->db->fetch_object($totalsResult)->total;
198
199 $tmp = $obj_ret;
200 $obj_ret = [];
201
202 $obj_ret['data'] = $tmp;
203 $obj_ret['pagination'] = [
204 'total' => (int) $total,
205 'page' => $page, //count starts from 0
206 'page_count' => ceil((int) $total / $limit),
207 'limit' => $limit
208 ];
209 }
210
211 return $obj_ret;
212 }
213
222 public function post($request_data = null)
223 {
224 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
225 throw new RestException(403, "Insufficiant rights");
226 }
227 // Check mandatory fields
228 $result = $this->_validate($request_data);
229
230 foreach ($request_data as $field => $value) {
231 if ($field === 'caller') {
232 // 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
233 $this->shipment->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
234 continue;
235 }
236
237 $this->shipment->$field = $this->_checkValForAPI($field, $value, $this->shipment);
238 }
239 if (isset($request_data["lines"])) {
240 $lines = array();
241 foreach ($request_data["lines"] as $line) {
242 $shipmentline = new ExpeditionLigne($this->db);
243
244 $shipmentline->entrepot_id = (int) $line['entrepot_id'];
245 $shipmentline->fk_element = (int) ($line['fk_element'] ?? $line['origin_id']); // example: order id. this->origin is 'commande'
246 $shipmentline->origin_line_id = (int) ($line['fk_elementdet'] ?? $line['origin_line_id']); // example: order id
247 $shipmentline->fk_elementdet = (int) ($line['fk_elementdet'] ?? $line['origin_line_id']); // example: order line id
248 $shipmentline->origin_type = $line['element_type'] ?? $line['origin_type']; // example 'commande' or 'order'
249 $shipmentline->element_type = $line['element_type'] ?? $line['origin_type']; // example 'commande' or 'order'
250 $shipmentline->qty = (float) $line['qty'];
251 $shipmentline->rang = (int) $line['rang'];
252 $array_options = $line['array_options'];
253 if (is_array($array_options)) {
254 $shipmentline->array_options = $array_options;
255 }
256 $detail_batch = $line['detail_batch'];
257 if (is_array($detail_batch) || is_object($detail_batch)) {
258 $shipmentline->detail_batch = $detail_batch;
259 }
260 $lines[] = $shipmentline;
261 }
262 $this->shipment->lines = $lines;
263 }
264
265 if ($this->shipment->create(DolibarrApiAccess::$user) < 0) {
266 throw new RestException(500, "Error creating shipment", array_merge(array($this->shipment->error), $this->shipment->errors));
267 }
268
269 return $this->shipment->id;
270 }
271
272 // /**
273 // * Get lines of an shipment
274 // *
275 // * @param int $id Id of shipment
276 // *
277 // * @url GET {id}/lines
278 // *
279 // * @return int
280 // */
281 /*
282 public function getLines($id)
283 {
284 if(! DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
285 throw new RestException(403);
286 }
287
288 $result = $this->shipment->fetch($id);
289 if( ! $result ) {
290 throw new RestException(404, 'Shipment not found');
291 }
292
293 if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
294 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
295 }
296 $this->shipment->getLinesArray();
297 $result = array();
298 foreach ($this->shipment->lines as $line) {
299 array_push($result,$this->_cleanObjectDatas($line));
300 }
301 return $result;
302 }
303 */
304
305 // /**
306 // * Add a line to given shipment
307 // *
308 // * @param int $id Id of shipment to update
309 // * @param array $request_data ShipmentLine data
310 // * @phan-param ?array<string,string> $request_data
311 // * @phpstan-param ?array<string,string> $request_data
312 // *
313 // * @url POST {id}/lines
314 // *
315 // * @return int
316 // */
317 /*
318 public function postLine($id, $request_data = null)
319 {
320 if(! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
321 throw new RestException(403);
322 }
323
324 $result = $this->shipment->fetch($id);
325 if ( ! $result ) {
326 throw new RestException(404, 'Shipment not found');
327 }
328
329 if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
330 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
331 }
332
333 $request_data = (object) $request_data;
334
335 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
336 $request_data->label = sanitizeVal($request_data->label);
337
338 $updateRes = $this->shipment->addline(
339 $request_data->desc,
340 $request_data->subprice,
341 $request_data->qty,
342 $request_data->tva_tx,
343 $request_data->localtax1_tx,
344 $request_data->localtax2_tx,
345 $request_data->fk_product,
346 $request_data->remise_percent,
347 $request_data->info_bits,
348 $request_data->fk_remise_except,
349 'HT',
350 0,
351 $request_data->date_start,
352 $request_data->date_end,
353 $request_data->product_type,
354 $request_data->rang,
355 $request_data->special_code,
356 $fk_parent_line,
357 $request_data->fk_fournprice,
358 $request_data->pa_ht,
359 $request_data->label,
360 $request_data->array_options,
361 $request_data->fk_unit,
362 $request_data->origin,
363 $request_data->origin_id,
364 $request_data->multicurrency_subprice
365 );
366
367 if ($updateRes > 0) {
368 return $updateRes;
369
370 }
371 return false;
372 }*/
373
374 // /**
375 // * Update a line to given shipment
376 // *
377 // * @param int $id Id of shipment to update
378 // * @param int $lineid Id of line to update
379 // * @param array $request_data ShipmentLine data
380 // *
381 // * @url PUT {id}/lines/{lineid}
382 // *
383 // * @return object
384 // */
385 /*
386 public function putLine($id, $lineid, $request_data = null)
387 {
388 if (! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
389 throw new RestException(403);
390 }
391
392 $result = $this->shipment->fetch($id);
393 if ( ! $result ) {
394 throw new RestException(404, 'Shipment not found');
395 }
396
397 if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
398 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
399 }
400
401 $request_data = (object) $request_data;
402
403 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
404 $request_data->label = sanitizeVal($request_data->label);
405
406 $updateRes = $this->shipment->updateline(
407 $lineid,
408 $request_data->desc,
409 $request_data->subprice,
410 $request_data->qty,
411 $request_data->remise_percent,
412 $request_data->tva_tx,
413 $request_data->localtax1_tx,
414 $request_data->localtax2_tx,
415 'HT',
416 $request_data->info_bits,
417 $request_data->date_start,
418 $request_data->date_end,
419 $request_data->product_type,
420 $request_data->fk_parent_line,
421 0,
422 $request_data->fk_fournprice,
423 $request_data->pa_ht,
424 $request_data->label,
425 $request_data->special_code,
426 $request_data->array_options,
427 $request_data->fk_unit,
428 $request_data->multicurrency_subprice
429 );
430
431 if ($updateRes > 0) {
432 $result = $this->get($id);
433 unset($result->line);
434 return $this->_cleanObjectDatas($result);
435 }
436 return false;
437 }*/
438
455 public function deleteLine($id, $lineid)
456 {
457 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
458 throw new RestException(403);
459 }
460
461 $result = $this->shipment->fetch($id);
462 if (!$result) {
463 throw new RestException(404, 'Shipment not found');
464 }
465
466 if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
467 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
468 }
469
470 // TODO Check the lineid $lineid is a line of object
471
472 $updateRes = $this->shipment->deleteLine(DolibarrApiAccess::$user, $lineid);
473 if ($updateRes > 0) {
474 return array(
475 'success' => array(
476 'code' => 200,
477 'message' => 'line ' .$lineid. ' deleted'
478 )
479 );
480 } else {
481 throw new RestException(405, $this->shipment->error);
482 }
483 }
484
494 public function put($id, $request_data = null)
495 {
496 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
497 throw new RestException(403);
498 }
499
500 $result = $this->shipment->fetch($id);
501 if (!$result) {
502 throw new RestException(404, 'Shipment not found');
503 }
504
505 if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
506 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
507 }
508 foreach ($request_data as $field => $value) {
509 if ($field == 'id') {
510 continue;
511 }
512 if ($field === 'caller') {
513 // 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
514 $this->shipment->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
515 continue;
516 }
517
518 if ($field == 'array_options' && is_array($value)) {
519 foreach ($value as $index => $val) {
520 $this->shipment->array_options[$index] = $this->_checkValExtrafieldsForAPI($index, $val, $this->shipment);
521 }
522 continue;
523 }
524 $this->shipment->$field = $this->_checkValForAPI($field, $value, $this->shipment);
525 }
526
527 if ($this->shipment->update(DolibarrApiAccess::$user) > 0) {
528 return $this->get($id);
529 } else {
530 throw new RestException(500, $this->shipment->error);
531 }
532 }
533
543 public function delete($id)
544 {
545 if (!DolibarrApiAccess::$user->hasRight('expedition', 'supprimer')) {
546 throw new RestException(403);
547 }
548 $result = $this->shipment->fetch($id);
549 if (!$result) {
550 throw new RestException(404, 'Shipment not found');
551 }
552
553 if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
554 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
555 }
556
557 if (!$this->shipment->delete(DolibarrApiAccess::$user)) {
558 throw new RestException(500, 'Error when deleting shipment : '.$this->shipment->error);
559 }
560
561 return array(
562 'success' => array(
563 'code' => 200,
564 'message' => 'Shipment deleted'
565 )
566 );
567 }
568
588 public function validate($id, $notrigger = 0)
589 {
590 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
591 throw new RestException(403);
592 }
593 $result = $this->shipment->fetch($id);
594 if (!$result) {
595 throw new RestException(404, 'Shipment not found');
596 }
597
598 if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
599 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
600 }
601
602 $result = $this->shipment->valid(DolibarrApiAccess::$user, $notrigger);
603 if ($result == 0) {
604 throw new RestException(304, 'Error nothing done. May be object is already validated');
605 }
606 if ($result < 0) {
607 throw new RestException(500, 'Error when validating Shipment: '.$this->shipment->error);
608 }
609
610 // Reload shipment
611 $result = $this->shipment->fetch($id);
612
613 $this->shipment->fetchObjectLinked();
614 return $this->_cleanObjectDatas($this->shipment);
615 }
616
617
618 // /**
619 // * Classify the shipment as invoiced
620 // *
621 // * @param int $id Id of the shipment
622 // *
623 // * @url POST {id}/setinvoiced
624 // *
625 // * @return int
626 // *
627 // * @throws RestException 400
628 // * @throws RestException 401
629 // * @throws RestException 404
630 // * @throws RestException 405
631 // */
632 /*
633 public function setinvoiced($id)
634 {
635
636 if(! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
637 throw new RestException(403);
638 }
639 if(empty($id)) {
640 throw new RestException(400, 'Shipment ID is mandatory');
641 }
642 $result = $this->shipment->fetch($id);
643 if( ! $result ) {
644 throw new RestException(404, 'Shipment not found');
645 }
646
647 $result = $this->shipment->classifyBilled(DolibarrApiAccess::$user);
648 if( $result < 0) {
649 throw new RestException(400, $this->shipment->error);
650 }
651 return $result;
652 }
653 */
654
655
656 // /**
657 // * Create a shipment using an existing order.
658 // *
659 // * @param int $orderid Id of the order
660 // *
661 // * @url POST /createfromorder/{orderid}
662 // *
663 // * @return int
664 // * @throws RestException 400
665 // * @throws RestException 401
666 // * @throws RestException 404
667 // * @throws RestException 405
668 // */
669 /*
670 public function createShipmentFromOrder($orderid)
671 {
672
673 require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
674
675 if(! DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
676 throw new RestException(403);
677 }
678 if(! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
679 throw new RestException(403);
680 }
681 if(empty($proposalid)) {
682 throw new RestException(400, 'Order ID is mandatory');
683 }
684
685 $order = new Commande($this->db);
686 $result = $order->fetch($proposalid);
687 if( ! $result ) {
688 throw new RestException(404, 'Order not found');
689 }
690
691 $result = $this->shipment->createFromOrder($order, DolibarrApiAccess::$user);
692 if( $result < 0) {
693 throw new RestException(405, $this->shipment->error);
694 }
695 $this->shipment->fetchObjectLinked();
696 return $this->_cleanObjectDatas($this->shipment);
697 }
698 */
699
710 public function close($id, $notrigger = 0)
711 {
712 if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
713 throw new RestException(403);
714 }
715
716 $result = $this->shipment->fetch($id);
717 if (!$result) {
718 throw new RestException(404, 'Shipment not found');
719 }
720
721 if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
722 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
723 }
724
725 $result = $this->shipment->setClosed();
726 if ($result == 0) {
727 throw new RestException(304, 'Error nothing done. May be object is already closed');
728 }
729 if ($result < 0) {
730 throw new RestException(500, 'Error when closing Order: '.$this->shipment->error);
731 }
732
733 // Reload shipment
734 $result = $this->shipment->fetch($id);
735
736 $this->shipment->fetchObjectLinked();
737
738 return $this->_cleanObjectDatas($this->shipment);
739 }
740
741 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
751 protected function _cleanObjectDatas($object)
752 {
753 // phpcs:enable
754 $object = parent::_cleanObjectDatas($object);
755
756 unset($object->canvas);
757
758 unset($object->thirdparty); // id already returned
759
760 unset($object->note);
761 unset($object->address);
762 unset($object->barcode_type);
763 unset($object->barcode_type_code);
764 unset($object->barcode_type_label);
765 unset($object->barcode_type_coder);
766
767 if (!empty($object->lines) && is_array($object->lines)) {
768 foreach ($object->lines as $line) {
769 if (is_array($line->detail_batch)) {
770 foreach ($line->detail_batch as $keytmp2 => $valtmp2) {
771 unset($line->detail_batch[$keytmp2]->db);
772 }
773 }
774 unset($line->canvas);
775
776 unset($line->tva_tx);
777 unset($line->vat_src_code);
778 unset($line->total_ht);
779 unset($line->total_ttc);
780 unset($line->total_tva);
781 unset($line->total_localtax1);
782 unset($line->total_localtax2);
783 unset($line->remise_percent);
784 }
785 }
786
787 return $object;
788 }
789
797 private function _validate($data)
798 {
799 if ($data === null) {
800 $data = array();
801 }
802 $shipment = array();
803 foreach (Shipments::$FIELDS as $field) {
804 if (!isset($data[$field])) {
805 throw new RestException(400, "$field field missing");
806 }
807 $shipment[$field] = $data[$field];
808 }
809 return $shipment;
810 }
811}
$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 lines of shipment.
close($id, $notrigger=0)
Classify the shipment as invoiced.
_validate($data)
Validate fields before create or update object.
put($id, $request_data=null)
Update shipment general fields (won't touch lines of shipment)
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $thirdparty_ids='', $sqlfilters='', $properties='', $pagination_data=false)
List shipments.
validate($id, $notrigger=0)
Validate a shipment.
__construct()
Constructor.
post($request_data=null)
Create shipment object.
_cleanObjectDatas($object)
Clean sensible object datas @phpstan-template T.
deleteLine($id, $lineid)
Get lines of an shipment.
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.