dolibarr  21.0.0-alpha
api_mos.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
3  * Copyright (C) 2019 Maxime Kohlhaas <maxime@atm-consulting.fr>
4  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
5  * Copyright (C) 2024 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 
21 use Luracast\Restler\RestException;
22 
23 require_once DOL_DOCUMENT_ROOT.'/mrp/class/mo.class.php';
24 
25 
38 class Mos extends DolibarrApi
39 {
43  public $mo;
44 
48  public function __construct()
49  {
50  global $db, $conf;
51  $this->db = $db;
52  $this->mo = new Mo($this->db);
53  }
54 
66  public function get($id)
67  {
68  if (!DolibarrApiAccess::$user->hasRight('mrp', 'read')) {
69  throw new RestException(403);
70  }
71 
72  $result = $this->mo->fetch($id);
73  if (!$result) {
74  throw new RestException(404, 'MO not found');
75  }
76 
77  if (!DolibarrApi::_checkAccessToResource('mrp', $this->mo->id, 'mrp_mo')) {
78  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
79  }
80 
81  return $this->_cleanObjectDatas($this->mo);
82  }
83 
84 
100  public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '', $properties = '')
101  {
102  if (!DolibarrApiAccess::$user->hasRight('mrp', 'read')) {
103  throw new RestException(403);
104  }
105 
106  $obj_ret = array();
107  $tmpobject = new Mo($this->db);
108 
109  $socid = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : 0;
110 
111  $restrictonsocid = 0; // Set to 1 if there is a field socid in table of object
112 
113  // If the internal user must only see his customers, force searching by him
114  $search_sale = 0;
115  if ($restrictonsocid && !DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socid) {
116  $search_sale = DolibarrApiAccess::$user->id;
117  }
118 
119  $sql = "SELECT t.rowid";
120  $sql .= " FROM ".MAIN_DB_PREFIX.$tmpobject->table_element." AS t";
121  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmpobject->table_element."_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 1 = 1";
123  if ($tmpobject->ismultientitymanaged) {
124  $sql .= ' AND t.entity IN ('.getEntity($tmpobject->element).')';
125  }
126  if ($restrictonsocid && $socid) {
127  $sql .= " AND t.fk_soc = ".((int) $socid);
128  }
129  // Search on sale representative
130  if ($search_sale && $search_sale != '-1') {
131  if ($search_sale == -2) {
132  $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
133  } elseif ($search_sale > 0) {
134  $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).")";
135  }
136  }
137  if ($sqlfilters) {
138  $errormessage = '';
139  $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
140  if ($errormessage) {
141  throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
142  }
143  }
144 
145  $sql .= $this->db->order($sortfield, $sortorder);
146  if ($limit) {
147  if ($page < 0) {
148  $page = 0;
149  }
150  $offset = $limit * $page;
151 
152  $sql .= $this->db->plimit($limit + 1, $offset);
153  }
154 
155  $result = $this->db->query($sql);
156  if ($result) {
157  $num = $this->db->num_rows($result);
158  $i = 0;
159  while ($i < $num) {
160  $obj = $this->db->fetch_object($result);
161  $tmp_object = new Mo($this->db);
162  if ($tmp_object->fetch($obj->rowid)) {
163  $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($tmp_object), $properties);
164  }
165  $i++;
166  }
167  } else {
168  throw new RestException(503, 'Error when retrieve MO list');
169  }
170 
171  return $obj_ret;
172  }
173 
180  public function post($request_data = null)
181  {
182  if (!DolibarrApiAccess::$user->hasRight('mrp', 'write')) {
183  throw new RestException(403);
184  }
185  // Check mandatory fields
186  $result = $this->_validate($request_data);
187 
188  foreach ($request_data as $field => $value) {
189  if ($field === 'caller') {
190  // 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
191  $this->mo->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
192  continue;
193  }
194 
195  $this->mo->$field = $this->_checkValForAPI($field, $value, $this->mo);
196  }
197 
198  $this->checkRefNumbering();
199 
200  if (!$this->mo->create(DolibarrApiAccess::$user)) {
201  throw new RestException(500, "Error creating MO", array_merge(array($this->mo->error), $this->mo->errors));
202  }
203  return $this->mo->id;
204  }
205 
213  public function put($id, $request_data = null)
214  {
215  if (!DolibarrApiAccess::$user->hasRight('mrp', 'write')) {
216  throw new RestException(403);
217  }
218 
219  $result = $this->mo->fetch($id);
220  if (!$result) {
221  throw new RestException(404, 'MO not found');
222  }
223 
224  if (!DolibarrApi::_checkAccessToResource('mrp', $this->mo->id, 'mrp_mo')) {
225  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
226  }
227 
228  foreach ($request_data as $field => $value) {
229  if ($field == 'id') {
230  continue;
231  }
232  if ($field === 'caller') {
233  // 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
234  $this->mo->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
235  continue;
236  }
237 
238  $this->mo->$field = $this->_checkValForAPI($field, $value, $this->mo);
239  }
240 
241  $this->checkRefNumbering();
242 
243  if ($this->mo->update(DolibarrApiAccess::$user) > 0) {
244  return $this->get($id);
245  } else {
246  throw new RestException(500, $this->mo->error);
247  }
248  }
249 
256  public function delete($id)
257  {
258  if (!DolibarrApiAccess::$user->hasRight('mrp', 'delete')) {
259  throw new RestException(403);
260  }
261  $result = $this->mo->fetch($id);
262  if (!$result) {
263  throw new RestException(404, 'MO not found');
264  }
265 
266  if (!DolibarrApi::_checkAccessToResource('mrp', $this->mo->id, 'mrp_mo')) {
267  throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
268  }
269 
270  if (!$this->mo->delete(DolibarrApiAccess::$user)) {
271  throw new RestException(500, 'Error when deleting MO : '.$this->mo->error);
272  }
273 
274  return array(
275  'success' => array(
276  'code' => 200,
277  'message' => 'MO deleted'
278  )
279  );
280  }
281 
282 
313  public function produceAndConsumeAll($id, $request_data = null)
314  {
315  global $langs;
316 
317  $error = 0;
318 
319  if (!DolibarrApiAccess::$user->hasRight('mrp', 'write')) {
320  throw new RestException(403, 'Not enough permission');
321  }
322  $result = $this->mo->fetch($id);
323  if (!$result) {
324  throw new RestException(404, 'MO not found');
325  }
326 
327  if ($this->mo->status != Mo::STATUS_VALIDATED && $this->mo->status != Mo::STATUS_INPROGRESS) {
328  throw new RestException(405, 'Error bad status of MO');
329  }
330 
331  // Code for consume and produce...
332  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
333  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
334  require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp_mo.lib.php';
335 
336  $stockmove = new MouvementStock($this->db);
337 
338  $labelmovement = '';
339  $codemovement = '';
340  $autoclose = 1;
341  $arraytoconsume = array();
342  $arraytoproduce = array();
343 
344  foreach ($request_data as $field => $value) {
345  if ($field == 'inventorylabel') {
346  $labelmovement = $value;
347  }
348  if ($field == 'inventorycode') {
349  $codemovement = $value;
350  }
351  if ($field == 'autoclose') {
352  $autoclose = $value;
353  }
354  if ($field == 'arraytoconsume') {
355  $arraytoconsume = $value;
356  }
357  if ($field == 'arraytoproduce') {
358  $arraytoproduce = $value;
359  }
360  if ($field === 'caller') {
361  // 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
362  $stockmove->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
363  continue;
364  }
365  }
366 
367  if (empty($labelmovement)) {
368  throw new RestException(500, "Field inventorylabel not provided");
369  }
370  if (empty($codemovement)) {
371  throw new RestException(500, "Field inventorycode not provided");
372  }
373 
374  $consumptioncomplete = true;
375  $productioncomplete = true;
376 
377  if (!empty($arraytoconsume) && !empty($arraytoproduce)) {
378  $pos = 0;
379  $arrayofarrayname = array("arraytoconsume","arraytoproduce");
380  foreach ($arrayofarrayname as $arrayname) {
381  foreach (${$arrayname} as $value) {
382  $tmpproduct = new Product($this->db);
383  if (empty($value["objectid"])) {
384  throw new RestException(500, "Field objectid required in ".$arrayname);
385  }
386  $tmpproduct->fetch($value["qty"]);
387  if (empty($value["qty"])) {
388  throw new RestException(500, "Field qty required in ".$arrayname);
389  }
390  if ($value["qty"] != 0) {
391  $qtytoprocess = $value["qty"];
392  if (isset($value["fk_warehouse"])) { // If there is a warehouse to set
393  if (!($value["fk_warehouse"] > 0)) { // If there is no warehouse set.
394  $error++;
395  throw new RestException(500, "Field fk_warehouse must be > 0 in ".$arrayname);
396  }
397  if ($tmpproduct->status_batch) {
398  $error++;
399  throw new RestException(500, "Product ".$tmpproduct->ref."must be in batch");
400  }
401  }
402  $idstockmove = 0;
403  if (!$error && $value["fk_warehouse"] > 0) {
404  // Record consumption to do and stock movement
405  $id_product_batch = 0;
406 
407  $stockmove->setOrigin($this->mo->element, $this->mo->id);
408 
409  if ($arrayname == 'arraytoconsume') {
410  $moline = new MoLine($this->db);
411  $moline->fk_mo = $this->mo->id;
412  $moline->position = $pos;
413  $moline->fk_product = $value["objectid"];
414  $moline->fk_warehouse = $value["fk_warehouse"];
415  $moline->qty = $qtytoprocess;
416  $moline->batch = (string) $tmpproduct->status_batch;
417  $moline->role = 'toproduce';
418  $moline->fk_mrp_production = "";
419  $moline->fk_stock_movement = $idstockmove;
420  $moline->fk_user_creat = DolibarrApiAccess::$user->id;
421 
422  $resultmoline = $moline->create(DolibarrApiAccess::$user);
423  if ($resultmoline <= 0) {
424  $error++;
425  throw new RestException(500, $moline->error);
426  }
427  $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $value["objectid"], $value["fk_warehouse"], $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
428  } else {
429  $moline = new MoLine($this->db);
430  $moline->fk_mo = $this->mo->id;
431  $moline->position = $pos;
432  $moline->fk_product = $value["objectid"];
433  $moline->fk_warehouse = $value["fk_warehouse"];
434  $moline->qty = $qtytoprocess;
435  $moline->batch = (string) $tmpproduct->status_batch;
436  $moline->role = 'toconsume';
437  $moline->fk_mrp_production = "";
438  $moline->fk_stock_movement = $idstockmove;
439  $moline->fk_user_creat = DolibarrApiAccess::$user->id;
440 
441  $resultmoline = $moline->create(DolibarrApiAccess::$user);
442  if ($resultmoline <= 0) {
443  $error++;
444  throw new RestException(500, $moline->error);
445  }
446  $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $value["objectid"], $value["fk_warehouse"], $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
447  }
448  if ($idstockmove < 0) {
449  $error++;
450  throw new RestException(500, $stockmove->error);
451  }
452  }
453  if (!$error) {
454  // Record consumption done
455  $moline = new MoLine($this->db);
456  $moline->fk_mo = $this->mo->id;
457  $moline->position = $pos;
458  $moline->fk_product = $value["objectid"];
459  $moline->fk_warehouse = $value["fk_warehouse"];
460  $moline->qty = $qtytoprocess;
461  $moline->batch = (string) $tmpproduct->status_batch;
462  if ($arrayname == "arraytoconsume") {
463  $moline->role = 'consumed';
464  } else {
465  $moline->role = 'produced';
466  }
467  $moline->fk_mrp_production = "";
468  $moline->fk_stock_movement = $idstockmove;
469  $moline->fk_user_creat = DolibarrApiAccess::$user->id;
470 
471  $resultmoline = $moline->create(DolibarrApiAccess::$user);
472  if ($resultmoline <= 0) {
473  $error++;
474  throw new RestException(500, $moline->error);
475  }
476 
477  $pos++;
478  }
479  }
480  }
481  }
482  if (!$error) {
483  if ($autoclose <= 0) {
484  $consumptioncomplete = false;
485  $productioncomplete = false;
486  }
487  }
488  } else {
489  $pos = 0;
490  foreach ($this->mo->lines as $line) {
491  if ($line->role == 'toconsume') {
492  $tmpproduct = new Product($this->db);
493  $tmpproduct->fetch($line->fk_product);
494  if ($line->qty != 0) {
495  $qtytoprocess = $line->qty;
496  if (isset($line->fk_warehouse)) { // If there is a warehouse to set
497  if (!($line->fk_warehouse > 0)) { // If there is no warehouse set.
498  $langs->load("errors");
499  $error++;
500  throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref));
501  }
502  if ($tmpproduct->status_batch) {
503  $langs->load("errors");
504  $error++;
505  throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref));
506  }
507  }
508  $idstockmove = 0;
509  if (!$error && $line->fk_warehouse > 0) {
510  // Record stock movement
511  $id_product_batch = 0;
512  $stockmove->origin_type = 'mo';
513  $stockmove->origin_id = $this->mo->id;
514  if ($qtytoprocess >= 0) {
515  $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
516  } else {
517  $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
518  }
519  if ($idstockmove < 0) {
520  $error++;
521  throw new RestException(500, $stockmove->error);
522  }
523  }
524  if (!$error) {
525  // Record consumption
526  $moline = new MoLine($this->db);
527  $moline->fk_mo = $this->mo->id;
528  $moline->position = $pos;
529  $moline->fk_product = $line->fk_product;
530  $moline->fk_warehouse = $line->fk_warehouse;
531  $moline->qty = $qtytoprocess;
532  $moline->batch = (string) $tmpproduct->status_batch;
533  $moline->role = 'consumed';
534  $moline->fk_mrp_production = $line->id;
535  $moline->fk_stock_movement = $idstockmove;
536  $moline->fk_user_creat = DolibarrApiAccess::$user->id;
537 
538  $resultmoline = $moline->create(DolibarrApiAccess::$user);
539  if ($resultmoline <= 0) {
540  $error++;
541  throw new RestException(500, $moline->error);
542  }
543 
544  $pos++;
545  }
546  }
547  }
548  }
549  $pos = 0;
550  foreach ($this->mo->lines as $line) {
551  if ($line->role == 'toproduce') {
552  $tmpproduct = new Product($this->db);
553  $tmpproduct->fetch($line->fk_product);
554  if ($line->qty != 0) {
555  $qtytoprocess = $line->qty;
556  if (isset($line->fk_warehouse)) { // If there is a warehouse to set
557  if (!($line->fk_warehouse > 0)) { // If there is no warehouse set.
558  $langs->load("errors");
559  $error++;
560  throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref));
561  }
562  if ($tmpproduct->status_batch) {
563  $langs->load("errors");
564  $error++;
565  throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref));
566  }
567  }
568  $idstockmove = 0;
569  if (!$error && $line->fk_warehouse > 0) {
570  // Record stock movement
571  $id_product_batch = 0;
572  $stockmove->origin_type = 'mo';
573  $stockmove->origin_id = $this->mo->id;
574  if ($qtytoprocess >= 0) {
575  $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
576  } else {
577  $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
578  }
579  if ($idstockmove < 0) {
580  $error++;
581  throw new RestException(500, $stockmove->error);
582  }
583  }
584  if (!$error) {
585  // Record consumption
586  $moline = new MoLine($this->db);
587  $moline->fk_mo = $this->mo->id;
588  $moline->position = $pos;
589  $moline->fk_product = $line->fk_product;
590  $moline->fk_warehouse = $line->fk_warehouse;
591  $moline->qty = $qtytoprocess;
592  $moline->batch = (string) $tmpproduct->status_batch;
593  $moline->role = 'produced';
594  $moline->fk_mrp_production = $line->id;
595  $moline->fk_stock_movement = $idstockmove;
596  $moline->fk_user_creat = DolibarrApiAccess::$user->id;
597 
598  $resultmoline = $moline->create(DolibarrApiAccess::$user);
599  if ($resultmoline <= 0) {
600  $error++;
601  throw new RestException(500, $moline->error);
602  }
603 
604  $pos++;
605  }
606  }
607  }
608  }
609 
610  if (!$error) {
611  if ($autoclose > 0) {
612  foreach ($this->mo->lines as $line) {
613  if ($line->role == 'toconsume') {
614  $arrayoflines = $this->mo->fetchLinesLinked('consumed', $line->id);
615  $alreadyconsumed = 0;
616  foreach ($arrayoflines as $line2) {
617  $alreadyconsumed += $line2['qty'];
618  }
619 
620  if ($alreadyconsumed < $line->qty) {
621  $consumptioncomplete = false;
622  }
623  }
624  if ($line->role == 'toproduce') {
625  $arrayoflines = $this->mo->fetchLinesLinked('produced', $line->id);
626  $alreadyproduced = 0;
627  foreach ($arrayoflines as $line2) {
628  $alreadyproduced += $line2['qty'];
629  }
630 
631  if ($alreadyproduced < $line->qty) {
632  $productioncomplete = false;
633  }
634  }
635  }
636  } else {
637  $consumptioncomplete = false;
638  $productioncomplete = false;
639  }
640  }
641  }
642 
643  // Update status of MO
644  dol_syslog("consumptioncomplete = ".json_encode($consumptioncomplete)." productioncomplete = ".json_encode($productioncomplete));
645  if ($consumptioncomplete && $productioncomplete) {
646  $result = $this->mo->setStatut(Mo::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
647  } else {
648  $result = $this->mo->setStatut(Mo::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
649  }
650  if ($result <= 0) {
651  throw new RestException(500, $this->mo->error);
652  }
653 
654  return $this->mo->id;
655  }
656 
689  public function produceAndConsume($id, $request_data = null)
690  {
691  if (!DolibarrApiAccess::$user->hasRight("mrp", "write")) {
692  throw new RestException(403, 'Not enough permission');
693  }
694  $result = $this->mo->fetch($id);
695  if (!$result) {
696  throw new RestException(404, 'MO not found');
697  }
698 
699  if ($this->mo->status != Mo::STATUS_VALIDATED && $this->mo->status != Mo::STATUS_INPROGRESS) {
700  throw new RestException(405, 'Error bad status of MO');
701  }
702 
703  // Code for consume and produce...
704  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
705  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
706  require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp_mo.lib.php';
707 
708  $stockmove = new MouvementStock($this->db);
709 
710  $labelmovement = '';
711  $codemovement = '';
712  $autoclose = 1;
713  $arraytoconsume = array();
714  $arraytoproduce = array();
715 
716  foreach ($request_data as $field => $value) {
717  if ($field == 'inventorylabel') {
718  $labelmovement = $value;
719  }
720  if ($field == 'inventorycode') {
721  $codemovement = $value;
722  }
723  if ($field == 'autoclose') {
724  $autoclose = $value;
725  }
726  if ($field == 'arraytoconsume') {
727  $arraytoconsume = $value;
728  }
729  if ($field == 'arraytoproduce') {
730  $arraytoproduce = $value;
731  }
732  if ($field === 'caller') {
733  // 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
734  $stockmove->context['caller'] = $request_data['caller'];
735  continue;
736  }
737  }
738 
739  if (empty($labelmovement)) {
740  throw new RestException(500, "Field inventorylabel not provided");
741  }
742  if (empty($codemovement)) {
743  throw new RestException(500, "Field inventorycode not provided");
744  }
745 
746  $this->db->begin();
747 
748  $pos = 0;
749  $arrayofarrayname = array("arraytoconsume","arraytoproduce");
750  foreach ($arrayofarrayname as $arrayname) {
751  foreach (${$arrayname} as $value) {
752  if (empty($value["objectid"])) {
753  throw new RestException(500, "Field objectid required in " . $arrayname);
754  }
755 
756  $molinetoprocess = new MoLine($this->db);
757  $tmpmolineid = $molinetoprocess->fetch($value["objectid"]);
758  if ($tmpmolineid <= 0) {
759  throw new RestException(500, "MoLine with rowid " . $value["objectid"] . " not exist.");
760  }
761 
762  $tmpproduct = new Product($this->db);
763  $tmpproduct->fetch($molinetoprocess->fk_product);
764  if ($tmpproduct->status_batch) {
765  throw new RestException(500, "Product " . $tmpproduct->ref . " must be in batch, this API can't handle it currently.");
766  }
767 
768  if (empty($value["qty"]) && $value["qty"] != 0) {
769  throw new RestException(500, "Field qty with lower or higher then 0 required in " . $arrayname);
770  }
771  $qtytoprocess = $value["qty"];
772 
773  if (isset($value["fk_warehouse"])) { // If there is a warehouse to set
774  if (!($value["fk_warehouse"] > 0)) { // If there is no warehouse set.
775  throw new RestException(500, "Field fk_warehouse required in " . $arrayname);
776  }
777  }
778  $fk_warehousetoprocess = $value["fk_warehouse"];
779 
780  $pricetoproduce = 0;
781  if (isset($value["pricetoproduce"])) { // If there is a price to produce set.
782  if ($value["pricetoproduce"] > 0) { // Only use prices grater then 0.
783  $pricetoproduce = $value["pricetoproduce"];
784  }
785  }
786 
787  $idstockmove = 0;
788 
789  // Record stock movement
790  $id_product_batch = 0;
791  $stockmove->origin_type = 'mo';
792  $stockmove->origin_id = $this->mo->id;
793  if ($arrayname == "arraytoconsume") {
794  if ($qtytoprocess >= 0) {
795  $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
796  } else {
797  $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
798  }
799  } else {
800  if ($qtytoprocess >= 0) {
801  $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, $pricetoproduce, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
802  } else {
803  $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
804  }
805  }
806  if ($idstockmove <= 0) {
807  throw new RestException(500, $stockmove->error);
808  }
809 
810  // Record consumption
811  $moline = new MoLine($this->db);
812  $moline->fk_mo = $this->mo->id;
813  $moline->position = $pos;
814  $moline->fk_product = $tmpproduct->id;
815  $moline->fk_warehouse = $fk_warehousetoprocess;
816  $moline->qty = $qtytoprocess;
817  $moline->batch = '';
818  $moline->fk_mrp_production = $molinetoprocess->id;
819  $moline->fk_stock_movement = $idstockmove;
820  $moline->fk_user_creat = DolibarrApiAccess::$user->id;
821 
822  if ($arrayname == "arraytoconsume") {
823  $moline->role = 'consumed';
824  } else {
825  $moline->role = 'produced';
826  }
827 
828  $resultmoline = $moline->create(DolibarrApiAccess::$user);
829  if ($resultmoline <= 0) {
830  throw new RestException(500, $moline->error);
831  }
832 
833  $pos++;
834  }
835  }
836 
837  $consumptioncomplete = true;
838  $productioncomplete = true;
839 
840  if ($autoclose > 0) {
841  // Refresh Lines after consumptions.
842  $this->mo->fetchLines();
843 
844  foreach ($this->mo->lines as $line) {
845  if ($line->role == 'toconsume') {
846  $arrayoflines = $this->mo->fetchLinesLinked('consumed', $line->id);
847  $alreadyconsumed = 0;
848  foreach ($arrayoflines as $line2) {
849  $alreadyconsumed += $line2['qty'];
850  }
851 
852  if ($alreadyconsumed < $line->qty) {
853  $consumptioncomplete = false;
854  }
855  }
856  if ($line->role == 'toproduce') {
857  $arrayoflines = $this->mo->fetchLinesLinked('produced', $line->id);
858  $alreadyproduced = 0;
859  foreach ($arrayoflines as $line2) {
860  $alreadyproduced += $line2['qty'];
861  }
862 
863  if ($alreadyproduced < $line->qty) {
864  $productioncomplete = false;
865  }
866  }
867  }
868  } else {
869  $consumptioncomplete = false;
870  $productioncomplete = false;
871  }
872 
873  // Update status of MO
874  dol_syslog("consumptioncomplete = " . (string) $consumptioncomplete . " productioncomplete = " . (string) $productioncomplete);
875  //var_dump("consumptioncomplete = ".$consumptioncomplete." productioncomplete = ".$productioncomplete);
876  if ($consumptioncomplete && $productioncomplete) {
877  $result = $this->mo->setStatut(Mo::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
878  } else {
879  $result = $this->mo->setStatut(Mo::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
880  }
881  if ($result <= 0) {
882  throw new RestException(500, $this->mo->error);
883  }
884 
885  $this->db->commit();
886  return $this->mo->id;
887  }
888 
889 
890  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
897  protected function _cleanObjectDatas($object)
898  {
899  // phpcs:enable
900  $object = parent::_cleanObjectDatas($object);
901 
902  unset($object->rowid);
903  unset($object->canvas);
904 
905  unset($object->name);
906  unset($object->lastname);
907  unset($object->firstname);
908  unset($object->civility_id);
909  unset($object->statut);
910  unset($object->state);
911  unset($object->state_id);
912  unset($object->state_code);
913  unset($object->region);
914  unset($object->region_code);
915  unset($object->country);
916  unset($object->country_id);
917  unset($object->country_code);
918  unset($object->barcode_type);
919  unset($object->barcode_type_code);
920  unset($object->barcode_type_label);
921  unset($object->barcode_type_coder);
922  unset($object->total_ht);
923  unset($object->total_tva);
924  unset($object->total_localtax1);
925  unset($object->total_localtax2);
926  unset($object->total_ttc);
927  unset($object->fk_account);
928  unset($object->comments);
929  unset($object->note);
930  unset($object->mode_reglement_id);
931  unset($object->cond_reglement_id);
932  unset($object->cond_reglement);
933  unset($object->shipping_method_id);
934  unset($object->fk_incoterms);
935  unset($object->label_incoterms);
936  unset($object->location_incoterms);
937 
938  // If object has lines, remove $db property
939  if (isset($object->lines) && is_array($object->lines) && count($object->lines) > 0) {
940  $nboflines = count($object->lines);
941  for ($i = 0; $i < $nboflines; $i++) {
942  $this->_cleanObjectDatas($object->lines[$i]);
943 
944  unset($object->lines[$i]->lines);
945  unset($object->lines[$i]->note);
946  }
947  }
948 
949  return $object;
950  }
951 
960  private function _validate($data)
961  {
962  $myobject = array();
963  foreach ($this->mo->fields as $field => $propfield) {
964  if (in_array($field, array('rowid', 'entity', 'date_creation', 'tms', 'fk_user_creat')) || $propfield['notnull'] != 1) {
965  continue; // Not a mandatory field
966  }
967  if (!isset($data[$field])) {
968  throw new RestException(400, "$field field missing");
969  }
970  $myobject[$field] = $data[$field];
971  }
972  return $myobject;
973  }
974 
980  private function checkRefNumbering()
981  {
982  $ref = substr($this->mo->ref, 1, 4);
983  if ($this->mo->status > 0 && $ref == 'PROV') {
984  throw new RestException(400, "Wrong naming scheme '(PROV%)' is only allowed on 'DRAFT' status. For automatic increment use 'auto' on the 'ref' field.");
985  }
986 
987  if (strtolower($this->mo->ref) == 'auto') {
988  if (empty($this->mo->id) && $this->mo->status == 0) {
989  $this->mo->ref = ''; // 'ref' will auto incremented with '(PROV' + newID + ')'
990  } else {
991  $this->mo->fetch_product();
992  $numref = $this->mo->getNextNumRef($this->mo->product);
993  $this->mo->ref = $numref;
994  }
995  }
996  }
997 }
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 for Mo.
Definition: mo.class.php:36
Class MoLine.
Definition: mo.class.php:1991
produceAndConsume($id, $request_data=null)
Produce and consume.
__construct()
Constructor.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $sqlfilters='', $properties='')
List Mos.
put($id, $request_data=null)
Update MO.
post($request_data=null)
Create MO object.
_cleanObjectDatas($object)
Clean sensible object datas.
produceAndConsumeAll($id, $request_data=null)
Produce and consume all.
checkRefNumbering()
Validate the ref field and get the next Number if it's necessary.
_validate($data)
Validate fields before create or update object.
Class to manage stock movements.
Class to manage products or services.
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:751
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
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.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))