dolibarr 20.0.0
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 $this->mo->$field = $this->_checkValForAPI($field, $value, $this->mo);
238 }
239
240 $this->checkRefNumbering();
241
242 if ($this->mo->update(DolibarrApiAccess::$user) > 0) {
243 return $this->get($id);
244 } else {
245 throw new RestException(500, $this->mo->error);
246 }
247 }
248
255 public function delete($id)
256 {
257 if (!DolibarrApiAccess::$user->hasRight('mrp', 'delete')) {
258 throw new RestException(403);
259 }
260 $result = $this->mo->fetch($id);
261 if (!$result) {
262 throw new RestException(404, 'MO not found');
263 }
264
265 if (!DolibarrApi::_checkAccessToResource('mrp', $this->mo->id, 'mrp_mo')) {
266 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
267 }
268
269 if (!$this->mo->delete(DolibarrApiAccess::$user)) {
270 throw new RestException(500, 'Error when deleting MO : '.$this->mo->error);
271 }
272
273 return array(
274 'success' => array(
275 'code' => 200,
276 'message' => 'MO deleted'
277 )
278 );
279 }
280
281
312 public function produceAndConsumeAll($id, $request_data = null)
313 {
314 global $langs;
315
316 $error = 0;
317
318 if (!DolibarrApiAccess::$user->hasRight('mrp', 'write')) {
319 throw new RestException(403, 'Not enough permission');
320 }
321 $result = $this->mo->fetch($id);
322 if (!$result) {
323 throw new RestException(404, 'MO not found');
324 }
325
326 if ($this->mo->status != Mo::STATUS_VALIDATED && $this->mo->status != Mo::STATUS_INPROGRESS) {
327 throw new RestException(405, 'Error bad status of MO');
328 }
329
330 // Code for consume and produce...
331 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
332 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
333 require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp_mo.lib.php';
334
335 $stockmove = new MouvementStock($this->db);
336
337 $labelmovement = '';
338 $codemovement = '';
339 $autoclose = 1;
340 $arraytoconsume = array();
341 $arraytoproduce = array();
342
343 foreach ($request_data as $field => $value) {
344 if ($field == 'inventorylabel') {
345 $labelmovement = $value;
346 }
347 if ($field == 'inventorycode') {
348 $codemovement = $value;
349 }
350 if ($field == 'autoclose') {
351 $autoclose = $value;
352 }
353 if ($field == 'arraytoconsume') {
354 $arraytoconsume = $value;
355 }
356 if ($field == 'arraytoproduce') {
357 $arraytoproduce = $value;
358 }
359 if ($field === 'caller') {
360 // 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
361 $stockmove->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
362 continue;
363 }
364 }
365
366 if (empty($labelmovement)) {
367 throw new RestException(500, "Field inventorylabel not provided");
368 }
369 if (empty($codemovement)) {
370 throw new RestException(500, "Field inventorycode not provided");
371 }
372
373 $consumptioncomplete = true;
374 $productioncomplete = true;
375
376 if (!empty($arraytoconsume) && !empty($arraytoproduce)) {
377 $pos = 0;
378 $arrayofarrayname = array("arraytoconsume","arraytoproduce");
379 foreach ($arrayofarrayname as $arrayname) {
380 foreach (${$arrayname} as $value) {
381 $tmpproduct = new Product($this->db);
382 if (empty($value["objectid"])) {
383 throw new RestException(500, "Field objectid required in ".$arrayname);
384 }
385 $tmpproduct->fetch($value["qty"]);
386 if (empty($value["qty"])) {
387 throw new RestException(500, "Field qty required in ".$arrayname);
388 }
389 if ($value["qty"] != 0) {
390 $qtytoprocess = $value["qty"];
391 if (isset($value["fk_warehouse"])) { // If there is a warehouse to set
392 if (!($value["fk_warehouse"] > 0)) { // If there is no warehouse set.
393 $error++;
394 throw new RestException(500, "Field fk_warehouse must be > 0 in ".$arrayname);
395 }
396 if ($tmpproduct->status_batch) {
397 $error++;
398 throw new RestException(500, "Product ".$tmpproduct->ref."must be in batch");
399 }
400 }
401 $idstockmove = 0;
402 if (!$error && $value["fk_warehouse"] > 0) {
403 // Record consumption to do and stock movement
404 $id_product_batch = 0;
405
406 $stockmove->setOrigin($this->mo->element, $this->mo->id);
407
408 if ($arrayname == 'arraytoconsume') {
409 $moline = new MoLine($this->db);
410 $moline->fk_mo = $this->mo->id;
411 $moline->position = $pos;
412 $moline->fk_product = $value["objectid"];
413 $moline->fk_warehouse = $value["fk_warehouse"];
414 $moline->qty = $qtytoprocess;
415 $moline->batch = $tmpproduct->status_batch;
416 $moline->role = 'toproduce';
417 $moline->fk_mrp_production = "";
418 $moline->fk_stock_movement = $idstockmove;
419 $moline->fk_user_creat = DolibarrApiAccess::$user->id;
420
421 $resultmoline = $moline->create(DolibarrApiAccess::$user);
422 if ($resultmoline <= 0) {
423 $error++;
424 throw new RestException(500, $moline->error);
425 }
426 $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $value["objectid"], $value["fk_warehouse"], $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
427 } else {
428 $moline = new MoLine($this->db);
429 $moline->fk_mo = $this->mo->id;
430 $moline->position = $pos;
431 $moline->fk_product = $value["objectid"];
432 $moline->fk_warehouse = $value["fk_warehouse"];
433 $moline->qty = $qtytoprocess;
434 $moline->batch = $tmpproduct->status_batch;
435 $moline->role = 'toconsume';
436 $moline->fk_mrp_production = "";
437 $moline->fk_stock_movement = $idstockmove;
438 $moline->fk_user_creat = DolibarrApiAccess::$user->id;
439
440 $resultmoline = $moline->create(DolibarrApiAccess::$user);
441 if ($resultmoline <= 0) {
442 $error++;
443 throw new RestException(500, $moline->error);
444 }
445 $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $value["objectid"], $value["fk_warehouse"], $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
446 }
447 if ($idstockmove < 0) {
448 $error++;
449 throw new RestException(500, $stockmove->error);
450 }
451 }
452 if (!$error) {
453 // Record consumption done
454 $moline = new MoLine($this->db);
455 $moline->fk_mo = $this->mo->id;
456 $moline->position = $pos;
457 $moline->fk_product = $value["objectid"];
458 $moline->fk_warehouse = $value["fk_warehouse"];
459 $moline->qty = $qtytoprocess;
460 $moline->batch = $tmpproduct->status_batch;
461 if ($arrayname == "arraytoconsume") {
462 $moline->role = 'consumed';
463 } else {
464 $moline->role = 'produced';
465 }
466 $moline->fk_mrp_production = "";
467 $moline->fk_stock_movement = $idstockmove;
468 $moline->fk_user_creat = DolibarrApiAccess::$user->id;
469
470 $resultmoline = $moline->create(DolibarrApiAccess::$user);
471 if ($resultmoline <= 0) {
472 $error++;
473 throw new RestException(500, $moline->error);
474 }
475
476 $pos++;
477 }
478 }
479 }
480 }
481 if (!$error) {
482 if ($autoclose <= 0) {
483 $consumptioncomplete = false;
484 $productioncomplete = false;
485 }
486 }
487 } else {
488 $pos = 0;
489 foreach ($this->mo->lines as $line) {
490 if ($line->role == 'toconsume') {
491 $tmpproduct = new Product($this->db);
492 $tmpproduct->fetch($line->fk_product);
493 if ($line->qty != 0) {
494 $qtytoprocess = $line->qty;
495 if (isset($line->fk_warehouse)) { // If there is a warehouse to set
496 if (!($line->fk_warehouse > 0)) { // If there is no warehouse set.
497 $langs->load("errors");
498 $error++;
499 throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref));
500 }
501 if ($tmpproduct->status_batch) {
502 $langs->load("errors");
503 $error++;
504 throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref));
505 }
506 }
507 $idstockmove = 0;
508 if (!$error && $line->fk_warehouse > 0) {
509 // Record stock movement
510 $id_product_batch = 0;
511 $stockmove->origin_type = 'mo';
512 $stockmove->origin_id = $this->mo->id;
513 if ($qtytoprocess >= 0) {
514 $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
515 } else {
516 $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
517 }
518 if ($idstockmove < 0) {
519 $error++;
520 throw new RestException(500, $stockmove->error);
521 }
522 }
523 if (!$error) {
524 // Record consumption
525 $moline = new MoLine($this->db);
526 $moline->fk_mo = $this->mo->id;
527 $moline->position = $pos;
528 $moline->fk_product = $line->fk_product;
529 $moline->fk_warehouse = $line->fk_warehouse;
530 $moline->qty = $qtytoprocess;
531 $moline->batch = $tmpproduct->status_batch;
532 $moline->role = 'consumed';
533 $moline->fk_mrp_production = $line->id;
534 $moline->fk_stock_movement = $idstockmove;
535 $moline->fk_user_creat = DolibarrApiAccess::$user->id;
536
537 $resultmoline = $moline->create(DolibarrApiAccess::$user);
538 if ($resultmoline <= 0) {
539 $error++;
540 throw new RestException(500, $moline->error);
541 }
542
543 $pos++;
544 }
545 }
546 }
547 }
548 $pos = 0;
549 foreach ($this->mo->lines as $line) {
550 if ($line->role == 'toproduce') {
551 $tmpproduct = new Product($this->db);
552 $tmpproduct->fetch($line->fk_product);
553 if ($line->qty != 0) {
554 $qtytoprocess = $line->qty;
555 if (isset($line->fk_warehouse)) { // If there is a warehouse to set
556 if (!($line->fk_warehouse > 0)) { // If there is no warehouse set.
557 $langs->load("errors");
558 $error++;
559 throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref));
560 }
561 if ($tmpproduct->status_batch) {
562 $langs->load("errors");
563 $error++;
564 throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref));
565 }
566 }
567 $idstockmove = 0;
568 if (!$error && $line->fk_warehouse > 0) {
569 // Record stock movement
570 $id_product_batch = 0;
571 $stockmove->origin_type = 'mo';
572 $stockmove->origin_id = $this->mo->id;
573 if ($qtytoprocess >= 0) {
574 $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
575 } else {
576 $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
577 }
578 if ($idstockmove < 0) {
579 $error++;
580 throw new RestException(500, $stockmove->error);
581 }
582 }
583 if (!$error) {
584 // Record consumption
585 $moline = new MoLine($this->db);
586 $moline->fk_mo = $this->mo->id;
587 $moline->position = $pos;
588 $moline->fk_product = $line->fk_product;
589 $moline->fk_warehouse = $line->fk_warehouse;
590 $moline->qty = $qtytoprocess;
591 $moline->batch = $tmpproduct->status_batch;
592 $moline->role = 'produced';
593 $moline->fk_mrp_production = $line->id;
594 $moline->fk_stock_movement = $idstockmove;
595 $moline->fk_user_creat = DolibarrApiAccess::$user->id;
596
597 $resultmoline = $moline->create(DolibarrApiAccess::$user);
598 if ($resultmoline <= 0) {
599 $error++;
600 throw new RestException(500, $moline->error);
601 }
602
603 $pos++;
604 }
605 }
606 }
607 }
608
609 if (!$error) {
610 if ($autoclose > 0) {
611 foreach ($this->mo->lines as $line) {
612 if ($line->role == 'toconsume') {
613 $arrayoflines = $this->mo->fetchLinesLinked('consumed', $line->id);
614 $alreadyconsumed = 0;
615 foreach ($arrayoflines as $line2) {
616 $alreadyconsumed += $line2['qty'];
617 }
618
619 if ($alreadyconsumed < $line->qty) {
620 $consumptioncomplete = false;
621 }
622 }
623 if ($line->role == 'toproduce') {
624 $arrayoflines = $this->mo->fetchLinesLinked('produced', $line->id);
625 $alreadyproduced = 0;
626 foreach ($arrayoflines as $line2) {
627 $alreadyproduced += $line2['qty'];
628 }
629
630 if ($alreadyproduced < $line->qty) {
631 $productioncomplete = false;
632 }
633 }
634 }
635 } else {
636 $consumptioncomplete = false;
637 $productioncomplete = false;
638 }
639 }
640 }
641
642 // Update status of MO
643 dol_syslog("consumptioncomplete = ".json_encode($consumptioncomplete)." productioncomplete = ".json_encode($productioncomplete));
644 if ($consumptioncomplete && $productioncomplete) {
645 $result = $this->mo->setStatut(Mo::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
646 } else {
647 $result = $this->mo->setStatut(Mo::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
648 }
649 if ($result <= 0) {
650 throw new RestException(500, $this->mo->error);
651 }
652
653 return $this->mo->id;
654 }
655
688 public function produceAndConsume($id, $request_data = null)
689 {
690 if (!DolibarrApiAccess::$user->hasRight("mrp", "write")) {
691 throw new RestException(403, 'Not enough permission');
692 }
693 $result = $this->mo->fetch($id);
694 if (!$result) {
695 throw new RestException(404, 'MO not found');
696 }
697
698 if ($this->mo->status != Mo::STATUS_VALIDATED && $this->mo->status != Mo::STATUS_INPROGRESS) {
699 throw new RestException(405, 'Error bad status of MO');
700 }
701
702 // Code for consume and produce...
703 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
704 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
705 require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp_mo.lib.php';
706
707 $stockmove = new MouvementStock($this->db);
708
709 $labelmovement = '';
710 $codemovement = '';
711 $autoclose = 1;
712 $arraytoconsume = array();
713 $arraytoproduce = array();
714
715 foreach ($request_data as $field => $value) {
716 if ($field == 'inventorylabel') {
717 $labelmovement = $value;
718 }
719 if ($field == 'inventorycode') {
720 $codemovement = $value;
721 }
722 if ($field == 'autoclose') {
723 $autoclose = $value;
724 }
725 if ($field == 'arraytoconsume') {
726 $arraytoconsume = $value;
727 }
728 if ($field == 'arraytoproduce') {
729 $arraytoproduce = $value;
730 }
731 if ($field === 'caller') {
732 // 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
733 $stockmove->context['caller'] = $request_data['caller'];
734 continue;
735 }
736 }
737
738 if (empty($labelmovement)) {
739 throw new RestException(500, "Field inventorylabel not provided");
740 }
741 if (empty($codemovement)) {
742 throw new RestException(500, "Field inventorycode not provided");
743 }
744
745 $this->db->begin();
746
747 $pos = 0;
748 $arrayofarrayname = array("arraytoconsume","arraytoproduce");
749 foreach ($arrayofarrayname as $arrayname) {
750 foreach (${$arrayname} as $value) {
751 if (empty($value["objectid"])) {
752 throw new RestException(500, "Field objectid required in " . $arrayname);
753 }
754
755 $molinetoprocess = new MoLine($this->db);
756 $tmpmolineid = $molinetoprocess->fetch($value["objectid"]);
757 if ($tmpmolineid <= 0) {
758 throw new RestException(500, "MoLine with rowid " . $value["objectid"] . " not exist.");
759 }
760
761 $tmpproduct = new Product($this->db);
762 $tmpproduct->fetch($molinetoprocess->fk_product);
763 if ($tmpproduct->status_batch) {
764 throw new RestException(500, "Product " . $tmpproduct->ref . " must be in batch, this API can't handle it currently.");
765 }
766
767 if (empty($value["qty"]) && $value["qty"] != 0) {
768 throw new RestException(500, "Field qty with lower or higher then 0 required in " . $arrayname);
769 }
770 $qtytoprocess = $value["qty"];
771
772 $fk_warehousetoprocess = 0;
773 if ($molinetoprocess->disable_stock_change == false) {
774 if (isset($value["fk_warehouse"])) { // If there is a warehouse to set
775 if (!($value["fk_warehouse"] > 0)) { // If there is no warehouse set.
776 throw new RestException(500, "Field fk_warehouse required in " . $arrayname);
777 }
778 }
779 $fk_warehousetoprocess = (int) $value["fk_warehouse"];
780 }
781
782 $pricetoproduce = 0;
783 if (isset($value["pricetoproduce"])) { // If there is a price to produce set.
784 if ($value["pricetoproduce"] > 0) { // Only use prices grater then 0.
785 $pricetoproduce = $value["pricetoproduce"];
786 }
787 }
788
789 $idstockmove = 0;
790
791 if ($molinetoprocess->disable_stock_change == false) {
792 // Record stock movement
793 $id_product_batch = 0;
794 $stockmove->origin_type = 'mo';
795 $stockmove->origin_id = $this->mo->id;
796 if ($arrayname == "arraytoconsume") {
797 if ($qtytoprocess >= 0) {
798 $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
799 } else {
800 $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
801 }
802 } else {
803 if ($qtytoprocess >= 0) {
804 $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, $pricetoproduce, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
805 } else {
806 $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $molinetoprocess->fk_product, $fk_warehousetoprocess, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
807 }
808 }
809 if ($idstockmove <= 0) {
810 throw new RestException(500, $stockmove->error);
811 }
812 }
813
814 // Record consumption
815 $moline = new MoLine($this->db);
816 $moline->fk_mo = $this->mo->id;
817 $moline->position = $pos;
818 $moline->fk_product = $tmpproduct->id;
819 $moline->fk_warehouse = $idstockmove > 0 ? $fk_warehousetoprocess : null;
820 $moline->qty = $qtytoprocess;
821 $moline->batch = '';
822 $moline->fk_mrp_production = $molinetoprocess->id;
823 $moline->fk_stock_movement = $idstockmove > 0 ? $idstockmove : null;
824 $moline->fk_user_creat = DolibarrApiAccess::$user->id;
825
826 if ($arrayname == "arraytoconsume") {
827 $moline->role = 'consumed';
828 } else {
829 $moline->role = 'produced';
830 }
831
832 $resultmoline = $moline->create(DolibarrApiAccess::$user);
833 if ($resultmoline <= 0) {
834 throw new RestException(500, $moline->error);
835 }
836
837 $pos++;
838 }
839 }
840
841 $consumptioncomplete = true;
842 $productioncomplete = true;
843
844 if ($autoclose > 0) {
845 // Refresh Lines after consumptions.
846 $this->mo->fetchLines();
847
848 foreach ($this->mo->lines as $line) {
849 if ($line->role == 'toconsume') {
850 $arrayoflines = $this->mo->fetchLinesLinked('consumed', $line->id);
851 $alreadyconsumed = 0;
852 foreach ($arrayoflines as $line2) {
853 $alreadyconsumed += $line2['qty'];
854 }
855
856 if ($alreadyconsumed < $line->qty) {
857 $consumptioncomplete = false;
858 }
859 }
860 if ($line->role == 'toproduce') {
861 $arrayoflines = $this->mo->fetchLinesLinked('produced', $line->id);
862 $alreadyproduced = 0;
863 foreach ($arrayoflines as $line2) {
864 $alreadyproduced += $line2['qty'];
865 }
866
867 if ($alreadyproduced < $line->qty) {
868 $productioncomplete = false;
869 }
870 }
871 }
872 } else {
873 $consumptioncomplete = false;
874 $productioncomplete = false;
875 }
876
877 // Update status of MO
878 dol_syslog("consumptioncomplete = " . (string) $consumptioncomplete . " productioncomplete = " . (string) $productioncomplete);
879 //var_dump("consumptioncomplete = ".$consumptioncomplete." productioncomplete = ".$productioncomplete);
880 if ($consumptioncomplete && $productioncomplete) {
881 $result = $this->mo->setStatut(Mo::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
882 } else {
883 $result = $this->mo->setStatut(Mo::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
884 }
885 if ($result <= 0) {
886 throw new RestException(500, $this->mo->error);
887 }
888
889 $this->db->commit();
890 return $this->mo->id;
891 }
892
893
894 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
901 protected function _cleanObjectDatas($object)
902 {
903 // phpcs:enable
904 $object = parent::_cleanObjectDatas($object);
905
906 unset($object->rowid);
907 unset($object->canvas);
908
909 unset($object->name);
910 unset($object->lastname);
911 unset($object->firstname);
912 unset($object->civility_id);
913 unset($object->statut);
914 unset($object->state);
915 unset($object->state_id);
916 unset($object->state_code);
917 unset($object->region);
918 unset($object->region_code);
919 unset($object->country);
920 unset($object->country_id);
921 unset($object->country_code);
922 unset($object->barcode_type);
923 unset($object->barcode_type_code);
924 unset($object->barcode_type_label);
925 unset($object->barcode_type_coder);
926 unset($object->total_ht);
927 unset($object->total_tva);
928 unset($object->total_localtax1);
929 unset($object->total_localtax2);
930 unset($object->total_ttc);
931 unset($object->fk_account);
932 unset($object->comments);
933 unset($object->note);
934 unset($object->mode_reglement_id);
935 unset($object->cond_reglement_id);
936 unset($object->cond_reglement);
937 unset($object->shipping_method_id);
938 unset($object->fk_incoterms);
939 unset($object->label_incoterms);
940 unset($object->location_incoterms);
941
942 // If object has lines, remove $db property
943 if (isset($object->lines) && is_array($object->lines) && count($object->lines) > 0) {
944 $nboflines = count($object->lines);
945 for ($i = 0; $i < $nboflines; $i++) {
946 $this->_cleanObjectDatas($object->lines[$i]);
947
948 unset($object->lines[$i]->lines);
949 unset($object->lines[$i]->note);
950 }
951 }
952
953 return $object;
954 }
955
964 private function _validate($data)
965 {
966 $myobject = array();
967 foreach ($this->mo->fields as $field => $propfield) {
968 if (in_array($field, array('rowid', 'entity', 'date_creation', 'tms', 'fk_user_creat')) || $propfield['notnull'] != 1) {
969 continue; // Not a mandatory field
970 }
971 if (!isset($data[$field])) {
972 throw new RestException(400, "$field field missing");
973 }
974 $myobject[$field] = $data[$field];
975 }
976 return $myobject;
977 }
978
984 private function checkRefNumbering()
985 {
986 $ref = substr($this->mo->ref, 1, 4);
987 if ($this->mo->status > 0 && $ref == 'PROV') {
988 throw new RestException(400, "Wrong naming scheme '(PROV%)' is only allowed on 'DRAFT' status. For automatic increment use 'auto' on the 'ref' field.");
989 }
990
991 if (strtolower($this->mo->ref) == 'auto') {
992 if (empty($this->mo->id) && $this->mo->status == 0) {
993 $this->mo->ref = ''; // 'ref' will auto incremented with '(PROV' + newID + ')'
994 } else {
995 $this->mo->fetch_product();
996 $numref = $this->mo->getNextNumRef($this->mo->product);
997 $this->mo->ref = $numref;
998 }
999 }
1000 }
1001}
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.