dolibarr  20.0.0-beta
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  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19  use Luracast\Restler\RestException;
20 
21  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
22 
29 class Shipments extends DolibarrApi
30 {
34  public static $FIELDS = array(
35  'socid',
36  'origin_id',
37  'origin_type',
38  );
39 
43  public $shipment;
44 
48  public function __construct()
49  {
50  global $db, $conf;
51  $this->db = $db;
52  $this->shipment = new Expedition($this->db);
53  }
54 
65  public function get($id)
66  {
67  if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
68  throw new RestException(403);
69  }
70 
71  $result = $this->shipment->fetch($id);
72  if (!$result) {
73  throw new RestException(404, 'Shipment not found');
74  }
75 
76  if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
77  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
78  }
79 
80  $this->shipment->fetchObjectLinked();
81  return $this->_cleanObjectDatas($this->shipment);
82  }
83 
84 
85 
102  public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $properties = '')
103  {
104  if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
105  throw new RestException(403);
106  }
107 
108  $obj_ret = array();
109 
110  // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
111  $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
112 
113  // If the internal user must only see his customers, force searching by him
114  $search_sale = 0;
115  if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
116  $search_sale = DolibarrApiAccess::$user->id;
117  }
118 
119  $sql = "SELECT t.rowid";
120  $sql .= " FROM ".MAIN_DB_PREFIX."expedition AS t";
121  $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
122  $sql .= ' WHERE t.entity IN ('.getEntity('expedition').')';
123  if ($socids) {
124  $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
125  }
126  // Search on sale representative
127  if ($search_sale && $search_sale != '-1') {
128  if ($search_sale == -2) {
129  $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
130  } elseif ($search_sale > 0) {
131  $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).")";
132  }
133  }
134  // Add sql filters
135  if ($sqlfilters) {
136  $errormessage = '';
137  $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
138  if ($errormessage) {
139  throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
140  }
141  }
142 
143  $sql .= $this->db->order($sortfield, $sortorder);
144  if ($limit) {
145  if ($page < 0) {
146  $page = 0;
147  }
148  $offset = $limit * $page;
149 
150  $sql .= $this->db->plimit($limit + 1, $offset);
151  }
152 
153  dol_syslog("API Rest request");
154  $result = $this->db->query($sql);
155 
156  if ($result) {
157  $num = $this->db->num_rows($result);
158  $min = min($num, ($limit <= 0 ? $num : $limit));
159  $i = 0;
160  while ($i < $min) {
161  $obj = $this->db->fetch_object($result);
162  $shipment_static = new Expedition($this->db);
163  if ($shipment_static->fetch($obj->rowid)) {
164  $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($shipment_static), $properties);
165  }
166  $i++;
167  }
168  } else {
169  throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
170  }
171 
172  return $obj_ret;
173  }
174 
181  public function post($request_data = null)
182  {
183  if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
184  throw new RestException(403, "Insuffisant rights");
185  }
186  // Check mandatory fields
187  $result = $this->_validate($request_data);
188 
189  foreach ($request_data as $field => $value) {
190  if ($field === 'caller') {
191  // 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
192  $this->shipment->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
193  continue;
194  }
195 
196  $this->shipment->$field = $this->_checkValForAPI($field, $value, $this->shipment);
197  }
198  if (isset($request_data["lines"])) {
199  $lines = array();
200  foreach ($request_data["lines"] as $line) {
201  $shipmentline = new ExpeditionLigne($this->db);
202 
203  $shipmentline->entrepot_id = $line['entrepot_id'];
204  $shipmentline->fk_element = $line['fk_element'] ?? $line['origin_id']; // example: order id. this->origin is 'commande'
205  $shipmentline->origin_line_id = $line['fk_elementdet'] ?? $line['origin_line_id']; // example: order id
206  $shipmentline->fk_elementdet = $line['fk_elementdet'] ?? $line['origin_line_id']; // example: order line id
207  $shipmentline->origin_type = $line['element_type'] ?? $line['origin_type']; // example 'commande' or 'order'
208  $shipmentline->element_type = $line['element_type'] ?? $line['origin_type']; // example 'commande' or 'order'
209  $shipmentline->qty = $line['qty'];
210  $shipmentline->rang = $line['rang'];
211  $shipmentline->array_options = $line['array_options'];
212  $shipmentline->detail_batch = $line['detail_batch'];
213 
214  $lines[] = $shipmentline;
215  }
216  $this->shipment->lines = $lines;
217  }
218 
219  if ($this->shipment->create(DolibarrApiAccess::$user) < 0) {
220  throw new RestException(500, "Error creating shipment", array_merge(array($this->shipment->error), $this->shipment->errors));
221  }
222 
223  return $this->shipment->id;
224  }
225 
226  // /**
227  // * Get lines of an shipment
228  // *
229  // * @param int $id Id of shipment
230  // *
231  // * @url GET {id}/lines
232  // *
233  // * @return int
234  // */
235  /*
236  public function getLines($id)
237  {
238  if(! DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
239  throw new RestException(403);
240  }
241 
242  $result = $this->shipment->fetch($id);
243  if( ! $result ) {
244  throw new RestException(404, 'Shipment not found');
245  }
246 
247  if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
248  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
249  }
250  $this->shipment->getLinesArray();
251  $result = array();
252  foreach ($this->shipment->lines as $line) {
253  array_push($result,$this->_cleanObjectDatas($line));
254  }
255  return $result;
256  }
257  */
258 
259  // /**
260  // * Add a line to given shipment
261  // *
262  // * @param int $id Id of shipment to update
263  // * @param array $request_data ShipmentLine data
264  // *
265  // * @url POST {id}/lines
266  // *
267  // * @return int
268  // */
269  /*
270  public function postLine($id, $request_data = null)
271  {
272  if(! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
273  throw new RestException(403);
274  }
275 
276  $result = $this->shipment->fetch($id);
277  if ( ! $result ) {
278  throw new RestException(404, 'Shipment not found');
279  }
280 
281  if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
282  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
283  }
284 
285  $request_data = (object) $request_data;
286 
287  $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
288  $request_data->label = sanitizeVal($request_data->label);
289 
290  $updateRes = $this->shipment->addline(
291  $request_data->desc,
292  $request_data->subprice,
293  $request_data->qty,
294  $request_data->tva_tx,
295  $request_data->localtax1_tx,
296  $request_data->localtax2_tx,
297  $request_data->fk_product,
298  $request_data->remise_percent,
299  $request_data->info_bits,
300  $request_data->fk_remise_except,
301  'HT',
302  0,
303  $request_data->date_start,
304  $request_data->date_end,
305  $request_data->product_type,
306  $request_data->rang,
307  $request_data->special_code,
308  $fk_parent_line,
309  $request_data->fk_fournprice,
310  $request_data->pa_ht,
311  $request_data->label,
312  $request_data->array_options,
313  $request_data->fk_unit,
314  $request_data->origin,
315  $request_data->origin_id,
316  $request_data->multicurrency_subprice
317  );
318 
319  if ($updateRes > 0) {
320  return $updateRes;
321 
322  }
323  return false;
324  }*/
325 
326  // /**
327  // * Update a line to given shipment
328  // *
329  // * @param int $id Id of shipment to update
330  // * @param int $lineid Id of line to update
331  // * @param array $request_data ShipmentLine data
332  // *
333  // * @url PUT {id}/lines/{lineid}
334  // *
335  // * @return object
336  // */
337  /*
338  public function putLine($id, $lineid, $request_data = null)
339  {
340  if (! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
341  throw new RestException(403);
342  }
343 
344  $result = $this->shipment->fetch($id);
345  if ( ! $result ) {
346  throw new RestException(404, 'Shipment not found');
347  }
348 
349  if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
350  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
351  }
352 
353  $request_data = (object) $request_data;
354 
355  $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
356  $request_data->label = sanitizeVal($request_data->label);
357 
358  $updateRes = $this->shipment->updateline(
359  $lineid,
360  $request_data->desc,
361  $request_data->subprice,
362  $request_data->qty,
363  $request_data->remise_percent,
364  $request_data->tva_tx,
365  $request_data->localtax1_tx,
366  $request_data->localtax2_tx,
367  'HT',
368  $request_data->info_bits,
369  $request_data->date_start,
370  $request_data->date_end,
371  $request_data->product_type,
372  $request_data->fk_parent_line,
373  0,
374  $request_data->fk_fournprice,
375  $request_data->pa_ht,
376  $request_data->label,
377  $request_data->special_code,
378  $request_data->array_options,
379  $request_data->fk_unit,
380  $request_data->multicurrency_subprice
381  );
382 
383  if ($updateRes > 0) {
384  $result = $this->get($id);
385  unset($result->line);
386  return $this->_cleanObjectDatas($result);
387  }
388  return false;
389  }*/
390 
405  public function deleteLine($id, $lineid)
406  {
407  if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
408  throw new RestException(403);
409  }
410 
411  $result = $this->shipment->fetch($id);
412  if (!$result) {
413  throw new RestException(404, 'Shipment not found');
414  }
415 
416  if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
417  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
418  }
419 
420  // TODO Check the lineid $lineid is a line of object
421 
422  $updateRes = $this->shipment->deleteLine(DolibarrApiAccess::$user, $lineid);
423  if ($updateRes > 0) {
424  return array(
425  'success' => array(
426  'code' => 200,
427  'message' => 'line ' .$lineid. ' deleted'
428  )
429  );
430  } else {
431  throw new RestException(405, $this->shipment->error);
432  }
433  }
434 
442  public function put($id, $request_data = null)
443  {
444  if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
445  throw new RestException(403);
446  }
447 
448  $result = $this->shipment->fetch($id);
449  if (!$result) {
450  throw new RestException(404, 'Shipment not found');
451  }
452 
453  if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
454  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
455  }
456  foreach ($request_data as $field => $value) {
457  if ($field == 'id') {
458  continue;
459  }
460  if ($field === 'caller') {
461  // 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
462  $this->shipment->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
463  continue;
464  }
465 
466  $this->shipment->$field = $this->_checkValForAPI($field, $value, $this->shipment);
467  }
468 
469  if ($this->shipment->update(DolibarrApiAccess::$user) > 0) {
470  return $this->get($id);
471  } else {
472  throw new RestException(500, $this->shipment->error);
473  }
474  }
475 
483  public function delete($id)
484  {
485  if (!DolibarrApiAccess::$user->hasRight('expedition', 'supprimer')) {
486  throw new RestException(403);
487  }
488  $result = $this->shipment->fetch($id);
489  if (!$result) {
490  throw new RestException(404, 'Shipment not found');
491  }
492 
493  if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
494  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
495  }
496 
497  if (!$this->shipment->delete(DolibarrApiAccess::$user)) {
498  throw new RestException(500, 'Error when deleting shipment : '.$this->shipment->error);
499  }
500 
501  return array(
502  'success' => array(
503  'code' => 200,
504  'message' => 'Shipment deleted'
505  )
506  );
507  }
508 
528  public function validate($id, $notrigger = 0)
529  {
530  if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
531  throw new RestException(403);
532  }
533  $result = $this->shipment->fetch($id);
534  if (!$result) {
535  throw new RestException(404, 'Shipment not found');
536  }
537 
538  if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
539  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
540  }
541 
542  $result = $this->shipment->valid(DolibarrApiAccess::$user, $notrigger);
543  if ($result == 0) {
544  throw new RestException(304, 'Error nothing done. May be object is already validated');
545  }
546  if ($result < 0) {
547  throw new RestException(500, 'Error when validating Shipment: '.$this->shipment->error);
548  }
549 
550  // Reload shipment
551  $result = $this->shipment->fetch($id);
552 
553  $this->shipment->fetchObjectLinked();
554  return $this->_cleanObjectDatas($this->shipment);
555  }
556 
557 
558  // /**
559  // * Classify the shipment as invoiced
560  // *
561  // * @param int $id Id of the shipment
562  // *
563  // * @url POST {id}/setinvoiced
564  // *
565  // * @return int
566  // *
567  // * @throws RestException 400
568  // * @throws RestException 401
569  // * @throws RestException 404
570  // * @throws RestException 405
571  // */
572  /*
573  public function setinvoiced($id)
574  {
575 
576  if(! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
577  throw new RestException(403);
578  }
579  if(empty($id)) {
580  throw new RestException(400, 'Shipment ID is mandatory');
581  }
582  $result = $this->shipment->fetch($id);
583  if( ! $result ) {
584  throw new RestException(404, 'Shipment not found');
585  }
586 
587  $result = $this->shipment->classifyBilled(DolibarrApiAccess::$user);
588  if( $result < 0) {
589  throw new RestException(400, $this->shipment->error);
590  }
591  return $result;
592  }
593  */
594 
595 
596  // /**
597  // * Create a shipment using an existing order.
598  // *
599  // * @param int $orderid Id of the order
600  // *
601  // * @url POST /createfromorder/{orderid}
602  // *
603  // * @return int
604  // * @throws RestException 400
605  // * @throws RestException 401
606  // * @throws RestException 404
607  // * @throws RestException 405
608  // */
609  /*
610  public function createShipmentFromOrder($orderid)
611  {
612 
613  require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
614 
615  if(! DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
616  throw new RestException(403);
617  }
618  if(! DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
619  throw new RestException(403);
620  }
621  if(empty($proposalid)) {
622  throw new RestException(400, 'Order ID is mandatory');
623  }
624 
625  $order = new Commande($this->db);
626  $result = $order->fetch($proposalid);
627  if( ! $result ) {
628  throw new RestException(404, 'Order not found');
629  }
630 
631  $result = $this->shipment->createFromOrder($order, DolibarrApiAccess::$user);
632  if( $result < 0) {
633  throw new RestException(405, $this->shipment->error);
634  }
635  $this->shipment->fetchObjectLinked();
636  return $this->_cleanObjectDatas($this->shipment);
637  }
638  */
639 
650  public function close($id, $notrigger = 0)
651  {
652  if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
653  throw new RestException(403);
654  }
655 
656  $result = $this->shipment->fetch($id);
657  if (!$result) {
658  throw new RestException(404, 'Shipment not found');
659  }
660 
661  if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
662  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
663  }
664 
665  $result = $this->shipment->setClosed();
666  if ($result == 0) {
667  throw new RestException(304, 'Error nothing done. May be object is already closed');
668  }
669  if ($result < 0) {
670  throw new RestException(500, 'Error when closing Order: '.$this->shipment->error);
671  }
672 
673  // Reload shipment
674  $result = $this->shipment->fetch($id);
675 
676  $this->shipment->fetchObjectLinked();
677 
678  return $this->_cleanObjectDatas($this->shipment);
679  }
680 
681  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
688  protected function _cleanObjectDatas($object)
689  {
690  // phpcs:enable
691  $object = parent::_cleanObjectDatas($object);
692 
693  unset($object->canvas);
694 
695  unset($object->thirdparty); // id already returned
696 
697  unset($object->note);
698  unset($object->address);
699  unset($object->barcode_type);
700  unset($object->barcode_type_code);
701  unset($object->barcode_type_label);
702  unset($object->barcode_type_coder);
703 
704  if (!empty($object->lines) && is_array($object->lines)) {
705  foreach ($object->lines as $line) {
706  if (is_array($line->detail_batch)) {
707  foreach ($line->detail_batch as $keytmp2 => $valtmp2) {
708  unset($line->detail_batch[$keytmp2]->db);
709  }
710  }
711  unset($line->canvas);
712 
713  unset($line->tva_tx);
714  unset($line->vat_src_code);
715  unset($line->total_ht);
716  unset($line->total_ttc);
717  unset($line->total_tva);
718  unset($line->total_localtax1);
719  unset($line->total_localtax2);
720  unset($line->remise_percent);
721  }
722  }
723 
724  return $object;
725  }
726 
734  private function _validate($data)
735  {
736  $shipment = array();
737  foreach (Shipments::$FIELDS as $field) {
738  if (!isset($data[$field])) {
739  throw new RestException(400, "$field field missing");
740  }
741  $shipment[$field] = $data[$field];
742  }
743  return $shipment;
744  }
745 }
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
Class for API REST v1.
Definition: api.class.php:30
_filterObjectProperties($object, $properties)
Filter properties that will be returned on object.
Definition: api.class.php:136
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid')
Check access by user to a given resource.
Definition: api.class.php:369
_checkValForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
Definition: api.class.php:82
Class to manage shipments.
Class to manage lines of shipment.
close($id, $notrigger=0)
Close a shipment (Classify it as "Delivered")
_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='')
List shipments.
validate($id, $notrigger=0)
Validate a shipment.
__construct()
Constructor.
post($request_data=null)
Create shipment object.
_cleanObjectDatas($object)
Clean sensible object datas.
deleteLine($id, $lineid)
Delete a line to given shipment.
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
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.