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
21use Luracast\Restler\RestException;
22
23require_once DOL_DOCUMENT_ROOT.'/mrp/class/mo.class.php';
24
25
38class 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 = 0;
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 = 0;
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 = 0;
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 $fk_warehousetoprocess = 0;
774 if ($molinetoprocess->disable_stock_change == false) {
775 if (isset($value["fk_warehouse"])) { // If there is a warehouse to set
776 if (!($value["fk_warehouse"] > 0)) { // If there is no warehouse set.
777 throw new RestException(500, "Field fk_warehouse required in " . $arrayname);
778 }
779 }
780 $fk_warehousetoprocess = (int) $value["fk_warehouse"];
781 }
782
783 $pricetoproduce = 0;
784 if (isset($value["pricetoproduce"])) { // If there is a price to produce set.
785 if ($value["pricetoproduce"] > 0) { // Only use prices grater then 0.
786 $pricetoproduce = $value["pricetoproduce"];
787 }
788 }
789
790 $idstockmove = 0;
791
792 if ($molinetoprocess->disable_stock_change == false) {
793 // Record stock movement
794 $id_product_batch = 0;
795 $stockmove->origin_type = 'mo';
796 $stockmove->origin_id = $this->mo->id;
797 if ($arrayname == "arraytoconsume") {
798 if ($qtytoprocess >= 0) {
799 $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
800 } else {
801 $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
802 }
803 } else {
804 if ($qtytoprocess >= 0) {
805 $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, $pricetoproduce, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
806 } else {
807 $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
808 }
809 }
810 if ($idstockmove <= 0) {
811 throw new RestException(500, $stockmove->error);
812 }
813 }
814
815 // Record consumption
816 $moline = new MoLine($this->db);
817 $moline->fk_mo = $this->mo->id;
818 $moline->position = $pos;
819 $moline->fk_product = $tmpproduct->id;
820 $moline->fk_warehouse = $idstockmove > 0 ? $fk_warehousetoprocess : null;
821 $moline->qty = $qtytoprocess;
822 $moline->batch = '';
823 $moline->fk_mrp_production = $molinetoprocess->id;
824 $moline->fk_stock_movement = $idstockmove > 0 ? $idstockmove : null;
825 $moline->fk_user_creat = DolibarrApiAccess::$user->id;
826
827 if ($arrayname == "arraytoconsume") {
828 $moline->role = 'consumed';
829 } else {
830 $moline->role = 'produced';
831 }
832
833 $resultmoline = $moline->create(DolibarrApiAccess::$user);
834 if ($resultmoline <= 0) {
835 throw new RestException(500, $moline->error);
836 }
837
838 $pos++;
839 }
840 }
841
842 $consumptioncomplete = true;
843 $productioncomplete = true;
844
845 if ($autoclose > 0) {
846 // Refresh Lines after consumptions.
847 $this->mo->fetchLines();
848
849 foreach ($this->mo->lines as $line) {
850 if ($line->role == 'toconsume') {
851 $arrayoflines = $this->mo->fetchLinesLinked('consumed', $line->id);
852 $alreadyconsumed = 0;
853 foreach ($arrayoflines as $line2) {
854 $alreadyconsumed += $line2['qty'];
855 }
856
857 if ($alreadyconsumed < $line->qty) {
858 $consumptioncomplete = false;
859 }
860 }
861 if ($line->role == 'toproduce') {
862 $arrayoflines = $this->mo->fetchLinesLinked('produced', $line->id);
863 $alreadyproduced = 0;
864 foreach ($arrayoflines as $line2) {
865 $alreadyproduced += $line2['qty'];
866 }
867
868 if ($alreadyproduced < $line->qty) {
869 $productioncomplete = false;
870 }
871 }
872 }
873 } else {
874 $consumptioncomplete = false;
875 $productioncomplete = false;
876 }
877
878 // Update status of MO
879 dol_syslog("consumptioncomplete = " . (string) $consumptioncomplete . " productioncomplete = " . (string) $productioncomplete);
880 //var_dump("consumptioncomplete = ".$consumptioncomplete." productioncomplete = ".$productioncomplete);
881 if ($consumptioncomplete && $productioncomplete) {
882 $result = $this->mo->setStatut(Mo::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
883 } else {
884 $result = $this->mo->setStatut(Mo::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
885 }
886 if ($result <= 0) {
887 throw new RestException(500, $this->mo->error);
888 }
889
890 $this->db->commit();
891 return $this->mo->id;
892 }
893
894
895 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
902 protected function _cleanObjectDatas($object)
903 {
904 // phpcs:enable
905 $object = parent::_cleanObjectDatas($object);
906
907 unset($object->rowid);
908 unset($object->canvas);
909
910 unset($object->name);
911 unset($object->lastname);
912 unset($object->firstname);
913 unset($object->civility_id);
914 unset($object->statut);
915 unset($object->state);
916 unset($object->state_id);
917 unset($object->state_code);
918 unset($object->region);
919 unset($object->region_code);
920 unset($object->country);
921 unset($object->country_id);
922 unset($object->country_code);
923 unset($object->barcode_type);
924 unset($object->barcode_type_code);
925 unset($object->barcode_type_label);
926 unset($object->barcode_type_coder);
927 unset($object->total_ht);
928 unset($object->total_tva);
929 unset($object->total_localtax1);
930 unset($object->total_localtax2);
931 unset($object->total_ttc);
932 unset($object->fk_account);
933 unset($object->comments);
934 unset($object->note);
935 unset($object->mode_reglement_id);
936 unset($object->cond_reglement_id);
937 unset($object->cond_reglement);
938 unset($object->shipping_method_id);
939 unset($object->fk_incoterms);
940 unset($object->label_incoterms);
941 unset($object->location_incoterms);
942
943 // If object has lines, remove $db property
944 if (isset($object->lines) && is_array($object->lines) && count($object->lines) > 0) {
945 $nboflines = count($object->lines);
946 for ($i = 0; $i < $nboflines; $i++) {
947 $this->_cleanObjectDatas($object->lines[$i]);
948
949 unset($object->lines[$i]->lines);
950 unset($object->lines[$i]->note);
951 }
952 }
953
954 return $object;
955 }
956
965 private function _validate($data)
966 {
967 $myobject = array();
968 foreach ($this->mo->fields as $field => $propfield) {
969 if (in_array($field, array('rowid', 'entity', 'date_creation', 'tms', 'fk_user_creat')) || $propfield['notnull'] != 1) {
970 continue; // Not a mandatory field
971 }
972 if (!isset($data[$field])) {
973 throw new RestException(400, "$field field missing");
974 }
975 $myobject[$field] = $data[$field];
976 }
977 return $myobject;
978 }
979
985 private function checkRefNumbering()
986 {
987 $ref = substr($this->mo->ref, 1, 4);
988 if ($this->mo->status > 0 && $ref == 'PROV') {
989 throw new RestException(400, "Wrong naming scheme '(PROV%)' is only allowed on 'DRAFT' status. For automatic increment use 'auto' on the 'ref' field.");
990 }
991
992 if (strtolower($this->mo->ref) == 'auto') {
993 if (empty($this->mo->id) && $this->mo->status == 0) {
994 $this->mo->ref = ''; // 'ref' will auto incremented with '(PROV' + newID + ')'
995 } else {
996 $this->mo->fetch_product();
997 $numref = $this->mo->getNextNumRef($this->mo->product);
998 $this->mo->ref = $numref;
999 }
1000 }
1001 }
1002}
$id
Definition account.php:39
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:34
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.