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