dolibarr 19.0.3
mo.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2020 Lenin Rivas <lenin@leninrivas.com>
4 * Copyright (C) 2023 Frédéric France <frederic.france@free.fr>
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
26// Put here all includes required by your class file
27require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
28require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
29
33class Mo extends CommonObject
34{
38 public $element = 'mo';
39
43 public $table_element = 'mrp_mo';
44
48 public $ismultientitymanaged = 1;
49
53 public $isextrafieldmanaged = 1;
54
58 public $picto = 'mrp';
59
60
61 const STATUS_DRAFT = 0;
62 const STATUS_VALIDATED = 1; // To produce
63 const STATUS_INPROGRESS = 2;
64 const STATUS_PRODUCED = 3;
65 const STATUS_CANCELED = 9;
66
67
97 public $fields = array(
98 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
99 'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'position'=>5, 'notnull'=>1, 'default'=>'1', 'index'=>1),
100 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>4, 'position'=>10, 'notnull'=>1, 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object", 'showoncombobox'=>'1', 'noteditable'=>1),
101 'fk_bom' => array('type'=>'integer:Bom:bom/class/bom.class.php:0:(t.status:=:1)', 'filter'=>'active=1', 'label'=>'BOM', 'enabled'=>'$conf->bom->enabled', 'visible'=>1, 'position'=>33, 'notnull'=>-1, 'index'=>1, 'comment'=>"Original BOM", 'css'=>'minwidth100 maxwidth500', 'csslist'=>'tdoverflowmax150', 'picto'=>'bom'),
102 'mrptype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>1, 'position'=>34, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing', 1=>'Disassemble'), 'css'=>'minwidth150', 'csslist'=>'minwidth150 center'),
103 'fk_product' => array('type'=>'integer:Product:product/class/product.class.php:0', 'label'=>'Product', 'enabled'=>'isModEnabled("product")', 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'comment'=>"Product to produce", 'css'=>'maxwidth300', 'csslist'=>'tdoverflowmax100', 'picto'=>'product'),
104 'qty' => array('type'=>'real', 'label'=>'QtyToProduce', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'notnull'=>1, 'comment'=>"Qty to produce", 'css'=>'width75', 'default'=>1, 'isameasure'=>1),
105 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>42, 'notnull'=>-1, 'searchall'=>1, 'showoncombobox'=>'2', 'css'=>'maxwidth300', 'csslist'=>'tdoverflowmax200', 'alwayseditable'=>1),
106 'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php:1', 'label'=>'ThirdParty', 'picto'=>'company', 'enabled'=>'isModEnabled("societe")', 'visible'=>-1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'css'=>'maxwidth400', 'csslist'=>'tdoverflowmax150'),
107 'fk_project' => array('type'=>'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label'=>'Project', 'picto'=>'project', 'enabled'=>'$conf->project->enabled', 'visible'=>-1, 'position'=>51, 'notnull'=>-1, 'index'=>1, 'css'=>'minwidth200 maxwidth400', 'csslist'=>'tdoverflowmax100'),
108 'fk_warehouse' => array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php:0', 'label'=>'WarehouseForProduction', 'picto'=>'stock', 'enabled'=>'isModEnabled("stock")', 'visible'=>1, 'position'=>52, 'css'=>'maxwidth400', 'csslist'=>'tdoverflowmax200'),
109 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>61, 'notnull'=>-1,),
110 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>62, 'notnull'=>-1,),
111 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>500, 'notnull'=>1,),
112 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,),
113 'date_valid' => array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>502,),
114 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'position'=>510, 'notnull'=>1, 'foreignkey'=>'user.rowid', 'csslist'=>'tdoverflowmax100'),
115 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'position'=>511, 'notnull'=>-1, 'csslist'=>'tdoverflowmax100'),
116 'date_start_planned' => array('type'=>'datetime', 'label'=>'DateStartPlannedMo', 'enabled'=>1, 'visible'=>1, 'position'=>55, 'notnull'=>-1, 'index'=>1, 'help'=>'KeepEmptyForAsap', 'alwayseditable'=>1, 'csslist'=>'nowraponall'),
117 'date_end_planned' => array('type'=>'datetime', 'label'=>'DateEndPlannedMo', 'enabled'=>1, 'visible'=>1, 'position'=>56, 'notnull'=>-1, 'index'=>1, 'alwayseditable'=>1, 'csslist'=>'nowraponall'),
118 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
119 'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
120 'status' => array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>2, 'position'=>1000, 'default'=>0, 'notnull'=>1, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Validated', '2'=>'InProgress', '3'=>'StatusMOProduced', '9'=>'Canceled')),
121 'fk_parent_line' => array('type'=>'integer:MoLine:mrp/class/mo.class.php', 'label'=>'ParentMo', 'enabled'=>1, 'visible'=>0, 'position'=>1020, 'default'=>0, 'notnull'=>0, 'index'=>1,'showoncombobox'=>0),
122 );
123 public $rowid;
124 public $entity;
125 public $ref;
126
130 public $mrptype;
131 public $label;
132 public $qty;
133 public $fk_warehouse;
134 public $fk_soc;
135 public $socid;
136
140 public $note_public;
141
145 public $note_private;
146
150 public $date_creation;
151
155 public $date_valid;
156
160 public $tms;
161
162 public $fk_user_creat;
163 public $fk_user_modif;
164 public $import_key;
165 public $status;
166
170 public $fk_product;
171
175 public $product;
176
180 public $date_start_planned;
181
185 public $date_end_planned;
186
190 public $fk_bom;
191
195 public $bom;
196
200 public $fk_project;
201
206 public $oldQty;
207
208
209 // If this object has a subtable with lines
210
214 public $table_element_line = 'mrp_production';
215
219 public $fk_element = 'fk_mo';
220
224 public $class_element_line = 'MoLine';
225
229 protected $childtables = array();
230
234 protected $childtablesoncascade = array('mrp_production');
235
239 public $lines = array();
240
244 public $line = array();
245
249 public $fk_parent_line;
250
254 public $tpl = array();
255
256
262 public function __construct(DoliDB $db)
263 {
264 global $conf, $langs;
265
266 $this->db = $db;
267
268 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
269 $this->fields['rowid']['visible'] = 0;
270 }
271 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
272 $this->fields['entity']['enabled'] = 0;
273 }
274
275 // Unset fields that are disabled
276 foreach ($this->fields as $key => $val) {
277 if (isset($val['enabled']) && empty($val['enabled'])) {
278 unset($this->fields[$key]);
279 }
280 }
281
282 // Translate some data of arrayofkeyval
283 foreach ($this->fields as $key => $val) {
284 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
285 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
286 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
287 }
288 }
289 }
290 }
291
299 public function create(User $user, $notrigger = false)
300 {
301 $error = 0;
302 $idcreated = 0;
303
304 // If kits feature is enabled and we don't allow kits into BOM and MO, we check that the product is not a kit/virtual product
305 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && !getDolGlobalString('ALLOW_USE_KITS_INTO_BOM_AND_MO') && $this->fk_product > 0) {
306 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
307 $tmpproduct = new Product($this->db);
308 $tmpproduct->fetch($this->fk_product);
309 if ($tmpproduct->hasFatherOrChild(1) > 0) {
310 $this->error = 'ErrorAVirtualProductCantBeUsedIntoABomOrMo';
311 $this->errors[] = $this->error;
312 return -1;
313 }
314 }
315
316 $this->db->begin();
317
318 if ($this->fk_bom > 0) {
319 // If there is a nown BOM, we force the type of MO to the type of BOM
320 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
321 $tmpbom = new BOM($this->db);
322 $tmpbom->fetch($this->fk_bom);
323
324 $this->mrptype = $tmpbom->bomtype;
325 }
326
327 if (!$error) {
328 $idcreated = $this->createCommon($user, $notrigger);
329 if ($idcreated <= 0) {
330 $error++;
331 }
332 }
333
334 if (!$error) {
335 $result = $this->createProduction($user, $notrigger); // Insert lines from BOM
336 if ($result <= 0) {
337 $error++;
338 }
339 }
340
341 if (!$error) {
342 $this->db->commit();
343 return $idcreated;
344 } else {
345 $this->db->rollback();
346 return -1;
347 }
348 }
349
357 public function createFromClone(User $user, $fromid)
358 {
359 global $langs, $extrafields;
360 $error = 0;
361
362 dol_syslog(__METHOD__, LOG_DEBUG);
363
364 $object = new self($this->db);
365
366 $this->db->begin();
367
368 // Load source object
369 $result = $object->fetchCommon($fromid);
370 if ($result > 0 && !empty($object->table_element_line)) {
371 $object->fetchLines();
372 }
373
374 // get lines so they will be clone
375 //foreach($this->lines as $line)
376 // $line->fetch_optionals();
377
378 // Reset some properties
379 unset($object->id);
380 unset($object->fk_user_creat);
381 unset($object->import_key);
382
383 // We make $object->lines empty to sort it without produced and consumed lines
384 $TLines = $object->lines;
385 $object->lines = array();
386
387 // Remove produced and consumed lines
388 foreach ($TLines as $key => $line) {
389 if (in_array($line->role, array('consumed', 'produced'))) {
390 unset($object->lines[$key]);
391 } else {
392 $object->lines[] = $line;
393 }
394 }
395
396
397 // Clear fields
398 $object->ref = empty($this->fields['ref']['default']) ? "copy_of_".$object->ref : $this->fields['ref']['default'];
399 $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
400 $object->status = self::STATUS_DRAFT;
401 // ...
402 // Clear extrafields that are unique
403 if (is_array($object->array_options) && count($object->array_options) > 0) {
404 $extrafields->fetch_name_optionals_label($this->table_element);
405 foreach ($object->array_options as $key => $option) {
406 $shortkey = preg_replace('/options_/', '', $key);
407 if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
408 //var_dump($key);
409 //var_dump($clonedObj->array_options[$key]); exit;
410 unset($object->array_options[$key]);
411 }
412 }
413 }
414
415 // Create clone
416 $object->context['createfromclone'] = 'createfromclone';
417 $result = $object->createCommon($user);
418 if ($result < 0) {
419 $error++;
420 $this->error = $object->error;
421 $this->errors = $object->errors;
422 }
423
424 if (!$error) {
425 // copy internal contacts
426 if ($this->copy_linked_contact($object, 'internal') < 0) {
427 $error++;
428 }
429 }
430
431 if (!$error) {
432 // copy external contacts if same company
433 if (property_exists($this, 'socid') && $this->socid == $object->socid) {
434 if ($this->copy_linked_contact($object, 'external') < 0) {
435 $error++;
436 }
437 }
438 }
439
440 unset($object->context['createfromclone']);
441
442 // End
443 if (!$error) {
444 $this->db->commit();
445 return $object;
446 } else {
447 $this->db->rollback();
448 return -1;
449 }
450 }
451
459 public function fetch($id, $ref = null)
460 {
461 $result = $this->fetchCommon($id, $ref);
462 if ($result > 0 && !empty($this->table_element_line)) {
463 $this->fetchLines();
464 }
465
466 $this->socid = $this->fk_soc;
467
468 return $result;
469 }
470
476 public function fetchLines()
477 {
478 $this->lines = array();
479
480 $result = $this->fetchLinesCommon();
481 return $result;
482 }
483
484
496 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
497 {
498 global $conf;
499
500 dol_syslog(__METHOD__, LOG_DEBUG);
501
502 $records = array();
503
504 $sql = 'SELECT ';
505 $sql .= $this->getFieldList();
506 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
507 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
508 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
509 } else {
510 $sql .= ' WHERE 1 = 1';
511 }
512 // Manage filter
513 $sqlwhere = array();
514 if (count($filter) > 0) {
515 foreach ($filter as $key => $value) {
516 if ($key == 't.rowid') {
517 $sqlwhere[] = $key." = ".((int) $value);
518 } elseif (strpos($key, 'date') !== false) {
519 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
520 } elseif ($key == 'customsql') {
521 $sqlwhere[] = $value;
522 } else {
523 $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
524 }
525 }
526 }
527 if (count($sqlwhere) > 0) {
528 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
529 }
530
531 if (!empty($sortfield)) {
532 $sql .= $this->db->order($sortfield, $sortorder);
533 }
534 if (!empty($limit)) {
535 $sql .= $this->db->plimit($limit, $offset);
536 }
537
538 $resql = $this->db->query($sql);
539 if ($resql) {
540 $num = $this->db->num_rows($resql);
541 $i = 0;
542 while ($i < min($limit, $num)) {
543 $obj = $this->db->fetch_object($resql);
544
545 $record = new self($this->db);
546 $record->setVarsFromFetchObj($obj);
547
548 $records[$record->id] = $record;
549
550 $i++;
551 }
552 $this->db->free($resql);
553
554 return $records;
555 } else {
556 $this->errors[] = 'Error '.$this->db->lasterror();
557 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
558
559 return -1;
560 }
561 }
562
570 public function fetchLinesLinked($role, $lineid = 0)
571 {
572 $resarray = array();
573 $mostatic = new MoLine($this->db);
574
575 $sql = 'SELECT ';
576 $sql .= $mostatic->getFieldList();
577 $sql .= ' FROM '.MAIN_DB_PREFIX.$mostatic->table_element.' as t';
578 $sql .= " WHERE t.role = '".$this->db->escape($role)."'";
579 if ($lineid > 0) {
580 $sql .= ' AND t.fk_mrp_production = '.((int) $lineid);
581 } else {
582 $sql .= 'AND t.fk_mo = '.((int) $this->id);
583 }
584
585 $resql = $this->db->query($sql);
586 if ($resql) {
587 $num = $this->db->num_rows($resql);
588
589 $i = 0;
590 while ($i < $num) {
591 $obj = $this->db->fetch_object($resql);
592 if ($obj) {
593 $resarray[] = array(
594 'rowid'=> $obj->rowid,
595 'date'=> $this->db->jdate($obj->date_creation),
596 'qty' => $obj->qty,
597 'role' => $obj->role,
598 'fk_product' => $obj->fk_product,
599 'fk_warehouse' => $obj->fk_warehouse,
600 'batch' => $obj->batch,
601 'fk_stock_movement' => $obj->fk_stock_movement,
602 'fk_unit' => $obj->fk_unit
603 );
604 }
605
606 $i++;
607 }
608
609 return $resarray;
610 } else {
611 $this->error = $this->db->lasterror();
612 return array();
613 }
614 }
615
616
622 public function countMovements()
623 {
624 $result = 0;
625
626 $sql = 'SELECT COUNT(rowid) as nb FROM '.MAIN_DB_PREFIX.'stock_mouvement as sm';
627 $sql .= " WHERE sm.origintype = 'mo' and sm.fk_origin = ".((int) $this->id);
628
629 $resql = $this->db->query($sql);
630 if ($resql) {
631 $num = $this->db->num_rows($resql);
632
633 $i = 0;
634 while ($i < $num) {
635 $obj = $this->db->fetch_object($resql);
636 if ($obj) {
637 $result = $obj->nb;
638 }
639
640 $i++;
641 }
642 } else {
643 $this->error = $this->db->lasterror();
644 }
645
646 return $result;
647 }
648
649
657 public function update(User $user, $notrigger = false)
658 {
659 $error = 0;
660
661 $this->db->begin();
662
663 $result = $this->updateCommon($user, $notrigger);
664 if ($result <= 0) {
665 $error++;
666 }
667
668 // Update the lines (the qty) to consume or to produce
669 $result = $this->updateProduction($user, $notrigger);
670 if ($result <= 0) {
671 $error++;
672 }
673
674 if (!$error) {
675 $this->db->commit();
676 return 1;
677 } else {
678 $this->db->rollback();
679 return -1;
680 }
681 }
682
683
691 public function createProduction(User $user, $notrigger = true)
692 {
693 $error = 0;
694 $role = "";
695
696 if ($this->status != self::STATUS_DRAFT) {
697 return -1;
698 }
699
700 $this->db->begin();
701
702 // Insert lines in mrp_production table from BOM data
703 if (!$error) {
704 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'mrp_production WHERE fk_mo = '.((int) $this->id);
705 $this->db->query($sql);
706
707 $moline = new MoLine($this->db);
708
709 // Line to produce
710 $moline->fk_mo = $this->id;
711 $moline->qty = $this->qty;
712 $moline->fk_product = $this->fk_product;
713 $moline->position = 1;
714 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
715 $tmpproduct = new Product($this->db);
716 $tmpproduct->fetch($this->fk_product);
717 $moline->fk_unit = $tmpproduct->fk_unit;
718
719 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to produce.
720 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
721 $bom = new BOM($this->db);
722 $bom->fetch($this->fk_bom);
723 if ($bom->bomtype == 1) {
724 $role = 'toproduce';
725 $moline->role = 'toconsume';
726 } else {
727 $role = 'toconsume';
728 $moline->role = 'toproduce';
729 }
730 } else {
731 if ($this->mrptype == 1) {
732 $moline->role = 'toconsume';
733 } else {
734 $moline->role = 'toproduce';
735 }
736 }
737
738 $resultline = $moline->create($user, false); // Never use triggers here
739 if ($resultline <= 0) {
740 $error++;
741 $this->error = $moline->error;
742 $this->errors = $moline->errors;
743 dol_print_error($this->db, $moline->error, $moline->errors);
744 }
745
746 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to consume.
747 if ($bom->id > 0) {
748 // Lines to consume
749 if (!$error) {
750 foreach ($bom->lines as $line) {
751 $moline = new MoLine($this->db);
752
753 $moline->fk_mo = $this->id;
754 $moline->origin_id = $line->id;
755 $moline->origin_type = 'bomline';
756 if (!empty($line->fk_unit)) {
757 $moline->fk_unit = $line->fk_unit;
758 }
759 if ($line->qty_frozen) {
760 $moline->qty = $line->qty; // Qty to consume does not depends on quantity to produce
761 } else {
762 $moline->qty = price2num(($line->qty / (!empty($bom->qty) ? $bom->qty : 1)) * $this->qty / (!empty($line->efficiency) ? $line->efficiency : 1), 'MS'); // Calculate with Qty to produce and more presition
763 }
764 if ($moline->qty <= 0) {
765 $error++;
766 $this->error = "BadValueForquantityToConsume";
767 $this->errors[] = $this->error;
768 break;
769 } else {
770 $moline->fk_product = $line->fk_product;
771 $moline->role = $role;
772 $moline->position = $line->position;
773 $moline->qty_frozen = $line->qty_frozen;
774 $moline->disable_stock_change = $line->disable_stock_change;
775 if (!empty($line->fk_default_workstation)) {
776 $moline->fk_default_workstation = $line->fk_default_workstation;
777 }
778
779 $resultline = $moline->create($user, false); // Never use triggers here
780 if ($resultline <= 0) {
781 $error++;
782 $this->error = $moline->error;
783 $this->errors[] = $moline->error;
784 $this->errors = array_merge($this->errors, $moline->errors);
785 dol_print_error($this->db, $moline->error, $moline->errors);
786 break;
787 }
788 }
789 }
790 }
791 }
792 }
793 }
794
795 if (!$error) {
796 $this->db->commit();
797 return 1;
798 } else {
799 $this->db->rollback();
800 return -1;
801 }
802 }
803
811 public function updateProduction(User $user, $notrigger = true)
812 {
813 $error = 0;
814
815 if ($this->status != self::STATUS_DRAFT) {
816 return 1;
817 }
818
819 $this->db->begin();
820
821 $oldQty = $this->oldQty;
822 $newQty = $this->qty;
823 if ($newQty != $oldQty && !empty($this->oldQty)) {
824 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "mrp_production WHERE fk_mo = " . (int) $this->id;
825 $resql = $this->db->query($sql);
826 if ($resql) {
827 while ($obj = $this->db->fetch_object($resql)) {
828 $moLine = new MoLine($this->db);
829 $res = $moLine->fetch($obj->rowid);
830 if (!$res) {
831 $error++;
832 }
833
834 if ($moLine->role == 'toconsume' || $moLine->role == 'toproduce') {
835 if (empty($moLine->qty_frozen)) {
836 $qty = $newQty * $moLine->qty / $oldQty;
837 $moLine->qty = price2num($qty, 'MS');
838 $res = $moLine->update($user);
839 if (!$res) {
840 $error++;
841 }
842 }
843 }
844 }
845 }
846 }
847 if (!$error) {
848 $this->db->commit();
849 return 1;
850 } else {
851 $this->db->rollback();
852 return -1;
853 }
854 }
855
856
865 public function delete(User $user, $notrigger = false, $also_cancel_consumed_and_produced_lines = false)
866 {
867 $error = 0;
868 $this->db->begin();
869
870 if ($also_cancel_consumed_and_produced_lines) {
871 $result = $this->cancelConsumedAndProducedLines($user, 0, false, $notrigger);
872 if ($result < 0) {
873 $error++;
874 }
875 }
876
877 if (!$error) {
878 $result = $this->deleteCommon($user, $notrigger);
879 if ($result < 0) {
880 $error++;
881 }
882 }
883
884 if ($error) {
885 $this->db->rollback();
886 return -1;
887 } else {
888 $this->db->commit();
889 return 1;
890 }
891 }
892
901 public function deleteLine(User $user, $idline, $notrigger = false)
902 {
903 global $langs;
904 $langs->loadLangs(array('stocks', 'mrp'));
905
906 if ($this->status < 0) {
907 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
908 return -2;
909 }
910 $productstatic = new Product($this->db);
911 $fk_movement = GETPOST('fk_movement', 'int');
912 $arrayoflines = $this->fetchLinesLinked('consumed', $idline); // Get lines consumed under the one to delete
913
914 $result = 0;
915
916 $this->db->begin();
917
918 if (!empty($arrayoflines)) {
919 // If there is child lines
920 $stockmove = new MouvementStock($this->db);
921 $stockmove->setOrigin($this->element, $this->id);
922
923 if (!empty($fk_movement)) {
924 // The fk_movement was not recorded so we try to guess the product and quantity to restore.
925 $moline = new MoLine($this->db);
926 $TArrayMoLine = $moline->fetchAll('', '', 1, 0, array('customsql' => 'fk_stock_movement = '.(int) $fk_movement));
927 $moline = array_shift($TArrayMoLine);
928
929 $movement = new MouvementStock($this->db);
930 $movement->fetch($fk_movement);
931 $productstatic->fetch($movement->product_id);
932 $qtytoprocess = $movement->qty;
933
934 // Reverse stock movement
935 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
936 $codemovementCancel = $langs->trans("StockIncrease");
937
938 if (($qtytoprocess >= 0)) {
939 $idstockmove = $stockmove->reception($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, '', '', $movement->batch, dol_now(), 0, $codemovementCancel);
940 } else {
941 $idstockmove = $stockmove->livraison($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $movement->batch, 0, $codemovementCancel);
942 }
943 if ($idstockmove < 0) {
944 $this->error++;
945 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
946 } else {
947 $result = $moline->delete($user, $notrigger);
948 }
949 } else {
950 // Loop on each child lines
951 foreach ($arrayoflines as $key => $arrayofline) {
952 $lineDetails = $arrayoflines[$key];
953 $productstatic->fetch($lineDetails['fk_product']);
954 $qtytoprocess = $lineDetails['qty'];
955
956 // Reverse stock movement
957 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
958 $codemovementCancel = $langs->trans("StockIncrease");
959
960
961 if ($qtytoprocess >= 0) {
962 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
963 } else {
964 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
965 }
966 if ($idstockmove < 0) {
967 $this->error++;
968 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
969 } else {
970 $moline = new MoLine($this->db);
971 $moline->fetch($lineDetails['rowid']);
972
973 $resdel = $moline->delete($user, $notrigger);
974 if ($resdel < 0) {
975 $this->error++;
976 setEventMessages($moline->error, $moline->errors, 'errors');
977 }
978 }
979 }
980
981 if (empty($this->error)) {
982 $result = $this->deleteLineCommon($user, $idline, $notrigger);
983 }
984 }
985 } else {
986 // No child lines
987 $result = $this->deleteLineCommon($user, $idline, $notrigger);
988 }
989
990 if (!empty($this->error) || $result <= 0) {
991 $this->db->rollback();
992 } else {
993 $this->db->commit();
994 }
995
996 return $result;
997 }
998
999
1007 public function getNextNumRef($prod)
1008 {
1009 global $langs, $conf;
1010 $langs->load("mrp");
1011
1012 if (getDolGlobalString('MRP_MO_ADDON')) {
1013 $mybool = false;
1014
1015 $file = getDolGlobalString('MRP_MO_ADDON') . ".php";
1016 $classname = $conf->global->MRP_MO_ADDON;
1017
1018 // Include file with class
1019 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1020 foreach ($dirmodels as $reldir) {
1021 $dir = dol_buildpath($reldir."core/modules/mrp/");
1022
1023 // Load file with numbering class (if found)
1024 $mybool |= @include_once $dir.$file;
1025 }
1026
1027 if ($mybool === false) {
1028 dol_print_error('', "Failed to include file ".$file);
1029 return '';
1030 }
1031
1032 $obj = new $classname();
1033 $numref = $obj->getNextValue($prod, $this);
1034
1035 if ($numref != "") {
1036 return $numref;
1037 } else {
1038 $this->error = $obj->error;
1039 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1040 return "";
1041 }
1042 } else {
1043 print $langs->trans("Error")." ".$langs->trans("Error_MRP_MO_ADDON_NotDefined");
1044 return "";
1045 }
1046 }
1047
1055 public function validate($user, $notrigger = 0)
1056 {
1057 global $conf, $langs;
1058
1059 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1060
1061 $error = 0;
1062
1063 // Protection
1064 if ($this->status == self::STATUS_VALIDATED) {
1065 dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
1066 return 0;
1067 }
1068
1069 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->create))
1070 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->mrp_advance->validate))))
1071 {
1072 $this->error='NotEnoughPermissions';
1073 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
1074 return -1;
1075 }*/
1076
1077 $now = dol_now();
1078
1079 $this->db->begin();
1080
1081 // Define new ref
1082 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1083 $this->fetch_product();
1084 $num = $this->getNextNumRef($this->product);
1085 } else {
1086 $num = $this->ref;
1087 }
1088 $this->newref = $num;
1089
1090 // Validate
1091 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1092 $sql .= " SET ref = '".$this->db->escape($num)."',";
1093 $sql .= " status = ".self::STATUS_VALIDATED.",";
1094 $sql .= " date_valid='".$this->db->idate($now)."',";
1095 $sql .= " fk_user_valid = ".$user->id;
1096 $sql .= " WHERE rowid = ".((int) $this->id);
1097
1098 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
1099 $resql = $this->db->query($sql);
1100 if (!$resql) {
1101 dol_print_error($this->db);
1102 $this->error = $this->db->lasterror();
1103 $error++;
1104 }
1105
1106 if (!$error && !$notrigger) {
1107 // Call trigger
1108 $result = $this->call_trigger('MRP_MO_VALIDATE', $user);
1109 if ($result < 0) {
1110 $error++;
1111 }
1112 // End call triggers
1113 }
1114
1115 if (!$error) {
1116 $this->oldref = $this->ref;
1117
1118 // Rename directory if dir was a temporary ref
1119 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1120 // Now we rename also files into index
1121 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'mrp/".$this->db->escape($this->newref)."'";
1122 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'mrp/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1123 $resql = $this->db->query($sql);
1124 if (!$resql) {
1125 $error++;
1126 $this->error = $this->db->lasterror();
1127 }
1128 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'mrp/".$this->db->escape($this->newref)."'";
1129 $sql .= " WHERE filepath = 'mrp/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1130 $resql = $this->db->query($sql);
1131 if (!$resql) {
1132 $error++;
1133 $this->error = $this->db->lasterror();
1134 }
1135
1136 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1137 $oldref = dol_sanitizeFileName($this->ref);
1138 $newref = dol_sanitizeFileName($num);
1139 $dirsource = $conf->mrp->dir_output.'/'.$oldref;
1140 $dirdest = $conf->mrp->dir_output.'/'.$newref;
1141 if (!$error && file_exists($dirsource)) {
1142 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
1143
1144 if (@rename($dirsource, $dirdest)) {
1145 dol_syslog("Rename ok");
1146 // Rename docs starting with $oldref with $newref
1147 $listoffiles = dol_dir_list($conf->mrp->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1148 foreach ($listoffiles as $fileentry) {
1149 $dirsource = $fileentry['name'];
1150 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1151 $dirsource = $fileentry['path'].'/'.$dirsource;
1152 $dirdest = $fileentry['path'].'/'.$dirdest;
1153 @rename($dirsource, $dirdest);
1154 }
1155 }
1156 }
1157 }
1158 }
1159
1160 // Set new ref and current status
1161 if (!$error) {
1162 $this->ref = $num;
1163 $this->status = self::STATUS_VALIDATED;
1164 }
1165
1166 if (!$error) {
1167 $this->db->commit();
1168 return 1;
1169 } else {
1170 $this->db->rollback();
1171 return -1;
1172 }
1173 }
1174
1182 public function setDraft($user, $notrigger = 0)
1183 {
1184 // Protection
1185 if ($this->status <= self::STATUS_DRAFT) {
1186 return 0;
1187 }
1188
1189 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1190 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1191 {
1192 $this->error='Permission denied';
1193 return -1;
1194 }*/
1195
1196 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'MRP_MO_UNVALIDATE');
1197 }
1198
1207 public function cancel($user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
1208 {
1209 // Protection
1210 if ($this->status != self::STATUS_VALIDATED && $this->status != self::STATUS_INPROGRESS) {
1211 return 0;
1212 }
1213
1214 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1215 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1216 {
1217 $this->error='Permission denied';
1218 return -1;
1219 }*/
1220
1221 $error = 0;
1222 $this->db->begin();
1223
1224 if ($also_cancel_consumed_and_produced_lines) {
1225 $result = $this->cancelConsumedAndProducedLines($user, 0, true, $notrigger);
1226 if ($result < 0) {
1227 $error++;
1228 }
1229 }
1230
1231 if (!$error) {
1232 $result = $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'MRP_MO_CANCEL');
1233 if ($result < 0) {
1234 $error++;
1235 }
1236 }
1237
1238 if ($error) {
1239 $this->db->rollback();
1240 return -1;
1241 } else {
1242 $this->db->commit();
1243 return 1;
1244 }
1245 }
1246
1254 public function reopen($user, $notrigger = 0)
1255 {
1256 // Protection
1257 if ($this->status != self::STATUS_PRODUCED && $this->status != self::STATUS_CANCELED) {
1258 return 0;
1259 }
1260
1261 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1262 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1263 {
1264 $this->error='Permission denied';
1265 return -1;
1266 }*/
1267
1268 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'MRP_MO_REOPEN');
1269 }
1270
1280 public function cancelConsumedAndProducedLines($user, $mode = 0, $also_delete_lines = false, $notrigger = 0)
1281 {
1282 global $langs;
1283
1284 if (!isModEnabled('stock')) {
1285 return 1;
1286 }
1287
1288 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1289 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php';
1290 $error = 0;
1291 $langs->load('stocks');
1292
1293 $this->db->begin();
1294
1295 // Cancel consumed lines
1296 if (empty($mode) || $mode == 1) {
1297 $arrayoflines = $this->fetchLinesLinked('consumed');
1298 if (!empty($arrayoflines)) {
1299 foreach ($arrayoflines as $key => $lineDetails) {
1300 $productstatic = new Product($this->db);
1301 $productstatic->fetch($lineDetails['fk_product']);
1302 $qtytoprocess = $lineDetails['qty'];
1303
1304 // Reverse stock movement
1305 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1306 $codemovementCancel = $langs->trans("StockIncrease");
1307
1308 $stockmove = new MouvementStock($this->db);
1309 $stockmove->setOrigin($this->element, $this->id);
1310 if ($qtytoprocess >= 0) {
1311 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1312 } else {
1313 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1314 }
1315 if ($idstockmove < 0) {
1316 $this->error = $stockmove->error;
1317 $this->errors = $stockmove->errors;
1318 $error++;
1319 break;
1320 }
1321
1322 if ($also_delete_lines) {
1323 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1324 if ($result < 0) {
1325 $error++;
1326 break;
1327 }
1328 }
1329 }
1330 }
1331 }
1332
1333 // Cancel produced lines
1334 if (empty($mode) || $mode == 2) {
1335 $arrayoflines = $this->fetchLinesLinked('produced');
1336 if (!empty($arrayoflines)) {
1337 foreach ($arrayoflines as $key => $lineDetails) {
1338 $productstatic = new Product($this->db);
1339 $productstatic->fetch($lineDetails['fk_product']);
1340 $qtytoprocess = $lineDetails['qty'];
1341
1342 // Reverse stock movement
1343 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1344 $codemovementCancel = $langs->trans("StockDecrease");
1345
1346 $stockmove = new MouvementStock($this->db);
1347 $stockmove->setOrigin($this->element, $this->id);
1348 if ($qtytoprocess >= 0) {
1349 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1350 } else {
1351 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1352 }
1353 if ($idstockmove < 0) {
1354 $this->error = $stockmove->error;
1355 $this->errors = $stockmove->errors;
1356 $error++;
1357 break;
1358 }
1359
1360 if ($also_delete_lines) {
1361 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1362 if ($result < 0) {
1363 $error++;
1364 break;
1365 }
1366 }
1367 }
1368 }
1369 }
1370
1371 if ($error) {
1372 $this->db->rollback();
1373 return -1;
1374 } else {
1375 $this->db->commit();
1376 return 1;
1377 }
1378 }
1379
1387 public function getTooltipContentArray($params)
1388 {
1389 global $conf, $langs;
1390
1391 $langs->loadLangs(['mrp', 'products']);
1392 $nofetch = isset($params['nofetch']) ? true : false;
1393
1394 $datas = [];
1395
1396 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ManufacturingOrder").'</u>';
1397 if (isset($this->status)) {
1398 $datas['picto'] .= ' '.$this->getLibStatut(5);
1399 }
1400 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1401 if (isset($this->label)) {
1402 $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1403 }
1404 if (isset($this->mrptype)) {
1405 $datas['type'] = '<br><b>'.$langs->trans('Type').':</b> '.$this->fields['mrptype']['arrayofkeyval'][$this->mrptype];
1406 }
1407 if (isset($this->qty)) {
1408 $datas['qty'] = '<br><b>'.$langs->trans('QtyToProduce').':</b> '.$this->qty;
1409 }
1410 if (!$nofetch && isset($this->fk_product)) {
1411 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1412 $product = new Product($this->db);
1413 $product->fetch($this->fk_product);
1414 $datas['product'] = '<br><b>'.$langs->trans('Product').':</b> '.$product->getNomUrl(1, '', 0, -1, 1);
1415 }
1416 if (!$nofetch && isset($this->fk_warehouse)) {
1417 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
1418 $warehouse = new Entrepot($this->db);
1419 $warehouse->fetch($this->fk_warehouse);
1420 $datas['warehouse'] = '<br><b>'.$langs->trans('WarehouseForProduction').':</b> '.$warehouse->getNomUrl(1, '', 0, 1);
1421 }
1422
1423 return $datas;
1424 }
1425
1436 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1437 {
1438 global $conf, $langs, $action, $hookmanager;
1439
1440 if (!empty($conf->dol_no_mouse_hover)) {
1441 $notooltip = 1; // Force disable tooltips
1442 }
1443
1444 $result = '';
1445 $params = [
1446 'id' => $this->id,
1447 'objecttype' => $this->element,
1448 'option' => $option,
1449 'nofetch' => 1,
1450 ];
1451 $classfortooltip = 'classfortooltip';
1452 $dataparams = '';
1453 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1454 $classfortooltip = 'classforajaxtooltip';
1455 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1456 $label = '';
1457 } else {
1458 $label = implode($this->getTooltipContentArray($params));
1459 }
1460
1461 $url = DOL_URL_ROOT.'/mrp/mo_card.php?id='.$this->id;
1462 if ($option == 'production') {
1463 $url = DOL_URL_ROOT.'/mrp/mo_production.php?id='.$this->id;
1464 }
1465
1466 if ($option != 'nolink') {
1467 // Add param to save lastsearch_values or not
1468 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1469 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1470 $add_save_lastsearch_values = 1;
1471 }
1472 if ($add_save_lastsearch_values) {
1473 $url .= '&save_lastsearch_values=1';
1474 }
1475 }
1476
1477 $linkclose = '';
1478 if (empty($notooltip)) {
1479 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1480 $label = $langs->trans("ShowMo");
1481 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1482 }
1483 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1484 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1485 } else {
1486 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1487 }
1488
1489 $linkstart = '<a href="'.$url.'"';
1490 $linkstart .= $linkclose.'>';
1491 $linkend = '</a>';
1492
1493 $result .= $linkstart;
1494 if ($withpicto) {
1495 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
1496 }
1497 if ($withpicto != 2) {
1498 $result .= $this->ref;
1499 }
1500 $result .= $linkend;
1501 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1502
1503 $hookmanager->initHooks(array('modao'));
1504 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1505 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1506 if ($reshook > 0) {
1507 $result = $hookmanager->resPrint;
1508 } else {
1509 $result .= $hookmanager->resPrint;
1510 }
1511
1512 return $result;
1513 }
1514
1521 public function getLibStatut($mode = 0)
1522 {
1523 return $this->LibStatut($this->status, $mode);
1524 }
1525
1526 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1534 public function LibStatut($status, $mode = 0)
1535 {
1536 // phpcs:enable
1537 if (empty($this->labelStatus)) {
1538 global $langs;
1539 //$langs->load("mrp");
1540 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1541 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('ValidatedToProduce');
1542 $this->labelStatus[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1543 $this->labelStatus[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1544 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1545
1546 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1547 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
1548 $this->labelStatusShort[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1549 $this->labelStatusShort[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1550 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1551 }
1552
1553 $statusType = 'status'.$status;
1554 if ($status == self::STATUS_VALIDATED) {
1555 $statusType = 'status1';
1556 }
1557 if ($status == self::STATUS_INPROGRESS) {
1558 $statusType = 'status4';
1559 }
1560 if ($status == self::STATUS_PRODUCED) {
1561 $statusType = 'status6';
1562 }
1563 if ($status == self::STATUS_CANCELED) {
1564 $statusType = 'status9';
1565 }
1566
1567 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1568 }
1569
1576 public function info($id)
1577 {
1578 $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1579 $sql .= ' fk_user_creat, fk_user_modif';
1580 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1581 $sql .= ' WHERE t.rowid = '.((int) $id);
1582 $result = $this->db->query($sql);
1583 if ($result) {
1584 if ($this->db->num_rows($result)) {
1585 $obj = $this->db->fetch_object($result);
1586
1587 $this->id = $obj->rowid;
1588
1589 $this->user_creation_id = $obj->fk_user_creat;
1590 $this->user_modification_id = $obj->fk_user_modif;
1591 $this->date_creation = $this->db->jdate($obj->datec);
1592 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1593 }
1594
1595 $this->db->free($result);
1596 } else {
1597 dol_print_error($this->db);
1598 }
1599 }
1600
1607 public function initAsSpecimen()
1608 {
1609 $this->initAsSpecimenCommon();
1610
1611 $this->lines = array();
1612 }
1613
1620 public function getLinesArray($rolefilter = '')
1621 {
1622 $this->lines = array();
1623
1624 $objectline = new MoLine($this->db);
1625
1626 $TFilters = array('customsql'=>'fk_mo = '.((int) $this->id));
1627 if (!empty($rolefilter)) {
1628 $TFilters['role'] = $rolefilter;
1629 }
1630 $result = $objectline->fetchAll('ASC', 'position', 0, 0, $TFilters);
1631
1632 if (is_numeric($result)) {
1633 $this->error = $objectline->error;
1634 $this->errors = $objectline->errors;
1635 return $result;
1636 } else {
1637 $this->lines = $result;
1638 return $this->lines;
1639 }
1640 }
1641
1653 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1654 {
1655 global $conf, $langs;
1656
1657 $langs->load("mrp");
1658
1659 if (!dol_strlen($modele)) {
1660 //$modele = 'standard';
1661 $modele = ''; // Remove this once a pdf_standard.php exists.
1662
1663 if ($this->model_pdf) {
1664 $modele = $this->model_pdf;
1665 } elseif (getDolGlobalString('MRP_MO_ADDON_PDF')) {
1666 $modele = getDolGlobalString('MRP_MO_ADDON_PDF');
1667 }
1668 }
1669
1670 $modelpath = "core/modules/mrp/doc/";
1671
1672 if (empty($modele)) {
1673 return 1; // Remove this once a pdf_standard.php exists.
1674 }
1675
1676 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1677 }
1678
1686 public function doScheduledJob()
1687 {
1688 global $conf, $langs;
1689
1690 //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1691
1692 $error = 0;
1693 $this->output = '';
1694 $this->error = '';
1695
1696 dol_syslog(__METHOD__, LOG_DEBUG);
1697
1698 $now = dol_now();
1699
1700 $this->db->begin();
1701
1702 // ...
1703
1704 $this->db->commit();
1705
1706 return $error;
1707 }
1708
1719 public function printOriginLinesList($restrictlist = '', $selectedLines = array())
1720 {
1721 global $langs, $hookmanager, $conf, $form, $action;
1722
1723 $langs->load('stocks');
1724 $text_stock_options = $langs->trans("RealStockDesc").'<br>';
1725 $text_stock_options .= $langs->trans("RealStockWillAutomaticallyWhen").'<br>';
1726 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT') || getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE') ? '- '.$langs->trans("DeStockOnShipment").'<br>' : '');
1727 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_VALIDATE_ORDER') ? '- '.$langs->trans("DeStockOnValidateOrder").'<br>' : '');
1728 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_BILL') ? '- '.$langs->trans("DeStockOnBill").'<br>' : '');
1729 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL') ? '- '.$langs->trans("ReStockOnBill").'<br>' : '');
1730 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER') ? '- '.$langs->trans("ReStockOnValidateOrder").'<br>' : '');
1731 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') ? '- '.$langs->trans("ReStockOnDispatchOrder").'<br>' : '');
1732 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION') || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE') ? '- '.$langs->trans("StockOnReception").'<br>' : '');
1733
1734 print '<tr class="liste_titre">';
1735 // Product or sub-bom
1736 print '<td class="linecoldescription">'.$langs->trans('Ref');
1737 if (getDolGlobalString('BOM_SUB_BOM')) {
1738 print ' &nbsp; <a id="show_all" href="#">'.img_picto('', 'folder-open', 'class="paddingright"').$langs->trans("ExpandAll").'</a>&nbsp;&nbsp;';
1739 print '<a id="hide_all" href="#">'.img_picto('', 'folder', 'class="paddingright"').$langs->trans("UndoExpandAll").'</a>&nbsp;';
1740 }
1741 print '</td>';
1742 // Qty
1743 print '<td class="right">'.$langs->trans('Qty');
1744 if ($this->bom->bomtype == 0) {
1745 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityOf", $this->bom->qty).')</span>';
1746 } else {
1747 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityToConsumeOf", $this->bom->qty).')</span>';
1748 }
1749 // Unit
1750 print '<td class="right">'.$langs->trans('Unit');
1751
1752 print '</td>';
1753 print '<td class="center">'.$form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1).'</td>';
1754 print '<td class="center">'.$form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc")).'</td>';
1755 print '<td class="center">'.$langs->trans('QtyFrozen').'</td>';
1756 print '<td class="center">'.$langs->trans('DisableStockChange').'</td>';
1757 print '<td class="center">'.$langs->trans('MoChildGenerate').'</td>';
1758 //print '<td class="center">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
1759 //print '<td class="center"></td>';
1760 print '</tr>';
1761 $i = 0;
1762
1763 if (!empty($this->lines)) {
1764 foreach ($this->lines as $line) {
1765 $reshook = 0;
1766 if (is_object($hookmanager)) {
1767 $parameters = array('line'=>$line, 'i'=>$i, 'restrictlist'=>$restrictlist, 'selectedLines'=> $selectedLines);
1768 if (!empty($line->fk_parent_line)) {
1769 $parameters['fk_parent_line'] = $line->fk_parent_line;
1770 }
1771 $reshook = $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1772 }
1773 if (empty($reshook)) {
1774 $this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
1775 }
1776
1777 $i++;
1778 }
1779 }
1780 }
1781
1782
1796 public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
1797 {
1798 $productstatic = new Product($this->db);
1799
1800 $this->tpl['id'] = $line->id;
1801
1802 $this->tpl['label'] = '';
1803 if (!empty($line->fk_product) && $line->fk_product > 0) {
1804 $productstatic->fetch($line->fk_product);
1805 $productstatic->load_virtual_stock();
1806 $this->tpl['label'] .= $productstatic->getNomUrl(1);
1807 //$this->tpl['label'].= ' - '.$productstatic->label;
1808 } else {
1809 // If origin MO line is not a product, but another MO
1810 // TODO
1811 }
1812
1813 $this->tpl['qty_bom'] = 1;
1814 if (is_object($this->bom) && $this->bom->qty > 1) {
1815 $this->tpl['qty_bom'] = $this->bom->qty;
1816 }
1817
1818 $this->tpl['stock'] = $productstatic->stock_reel;
1819 $this->tpl['seuil_stock_alerte'] = $productstatic->seuil_stock_alerte;
1820 $this->tpl['virtual_stock'] = $productstatic->stock_theorique;
1821 $this->tpl['qty'] = $line->qty;
1822 $this->tpl['fk_unit'] = $line->fk_unit;
1823 $this->tpl['qty_frozen'] = $line->qty_frozen;
1824 $this->tpl['disable_stock_change'] = $line->disable_stock_change;
1825 $this->tpl['efficiency'] = $line->efficiency;
1826
1827 global $conf; // used into template
1828 $res = include DOL_DOCUMENT_ROOT.'/mrp/tpl/originproductline.tpl.php';
1829 }
1830
1839 public static function replaceThirdparty($db, $origin_id, $dest_id)
1840 {
1841 $tables = array('mrp_mo');
1842
1843 return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1844 }
1845
1846
1852 public function getMoChilds()
1853 {
1854 $TMoChilds = array();
1855 $error = 0;
1856
1857 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_mo as mo_child";
1858 $sql.= " WHERE fk_parent_line IN ";
1859 $sql.= " (SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_production as line_parent";
1860 $sql.= " WHERE fk_mo=".((int) $this->id).")";
1861
1862 $resql = $this->db->query($sql);
1863
1864 if ($resql) {
1865 if ($this->db->num_rows($resql) > 0) {
1866 while ($obj = $this->db->fetch_object($resql)) {
1867 $MoChild = new Mo($this->db);
1868 $res = $MoChild->fetch($obj->rowid);
1869 if ($res > 0) {
1870 $TMoChilds[$MoChild->id] = $MoChild;
1871 } else {
1872 $error++;
1873 }
1874 }
1875 }
1876 } else {
1877 $error++;
1878 }
1879
1880 if ($error) {
1881 return -1;
1882 } else {
1883 return $TMoChilds;
1884 }
1885 }
1886
1893 public function getAllMoChilds($depth = 0)
1894 {
1895 if ($depth > 1000) {
1896 return -1;
1897 }
1898
1899 $TMoChilds = array();
1900 $error = 0;
1901
1902 $childMoList = $this->getMoChilds();
1903
1904 if ($childMoList == -1) {
1905 return -1;
1906 }
1907
1908 foreach ($childMoList as $childMo) {
1909 $TMoChilds[$childMo->id] = $childMo;
1910 }
1911
1912 foreach ($childMoList as $childMo) {
1913 $childMoChildren = $childMo->getAllMoChilds($depth + 1);
1914
1915 if ($childMoChildren == -1) {
1916 $error++;
1917 } else {
1918 foreach ($childMoChildren as $child) {
1919 $TMoChilds[$child->id] = $child;
1920 }
1921 }
1922 }
1923
1924 if ($error) {
1925 return -1;
1926 } else {
1927 return $TMoChilds;
1928 }
1929 }
1930
1931
1932
1938 public function getMoParent()
1939 {
1940 $MoParent = new Mo($this->db);
1941 $error = 0;
1942
1943 $sql = "SELECT lineparent.fk_mo as id_moparent FROM ".MAIN_DB_PREFIX."mrp_mo as mo";
1944 $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."mrp_production lineparent ON mo.fk_parent_line = lineparent.rowid";
1945 $sql.= " WHERE mo.rowid = ".((int) $this->id);
1946
1947 $resql = $this->db->query($sql);
1948
1949 if ($resql) {
1950 if ($this->db->num_rows($resql) > 0) {
1951 $obj = $this->db->fetch_object($resql);
1952 $res = $MoParent->fetch($obj->id_moparent);
1953 if ($res < 0) {
1954 $error++;
1955 }
1956 } else {
1957 return 0;
1958 }
1959 } else {
1960 $error++;
1961 }
1962
1963 if ($error) {
1964 return -1;
1965 } else {
1966 return $MoParent;
1967 }
1968 }
1969
1977 public function getKanbanView($option = '', $arraydata = null)
1978 {
1979 global $langs;
1980
1981 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1982
1983 $return = '<div class="box-flex-item box-flex-grow-zero">';
1984 $return .= '<div class="info-box info-box-sm">';
1985 $return .= '<span class="info-box-icon bg-infobox-action">';
1986 $return .= img_picto('', $this->picto);
1987 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
1988 $return .= '</span>';
1989 $return .= '<div class="info-box-content">';
1990 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
1991 if ($selected >= 0) {
1992 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1993 }
1994 if (!empty($arraydata['bom'])) {
1995 $return .= '<br><span class="info-box-label">'.$arraydata['bom']->getNomUrl(1).'</span>';
1996 }
1997 if (!empty($arraydata['product'])) {
1998 $return .= '<br><span class="info-box-label">'.$arraydata['product']->getNomUrl(1).'</span>';
1999 }
2000 if (property_exists($this, 'qty')) {
2001 $return .= '<br><span class="info-box-label">'.$langs->trans('Quantity').' : '.$this->qty.'</span>';
2002 }
2003 if (method_exists($this, 'getLibStatut')) {
2004 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
2005 }
2006 $return .= '</div>';
2007 $return .= '</div>';
2008 $return .= '</div>';
2009 return $return;
2010 }
2011}
2012
2017{
2021 public $element = 'mrp_production';
2022
2026 public $table_element = 'mrp_production';
2027
2031 public $ismultientitymanaged = 0;
2032
2036 public $isextrafieldmanaged = 1;
2037
2038 public $fields = array(
2039 'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
2040 'fk_mo' =>array('type'=>'integer', 'label'=>'Mo', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>15),
2041 'origin_id' =>array('type'=>'integer', 'label'=>'Origin', 'enabled'=>1, 'visible'=>-1, 'notnull'=>0, 'position'=>17),
2042 'origin_type' =>array('type'=>'varchar(10)', 'label'=>'Origin type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>0, 'position'=>18),
2043 'position' =>array('type'=>'integer', 'label'=>'Position', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>20),
2044 'fk_product' =>array('type'=>'integer', 'label'=>'Product', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>25),
2045 'fk_warehouse' =>array('type'=>'integer', 'label'=>'Warehouse', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
2046 'qty' =>array('type'=>'real', 'label'=>'Qty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
2047 'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'notnull' => 1, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
2048 'disable_stock_change' => array('type'=>'smallint', 'label'=>'DisableStockChange', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'notnull' => 1, 'position'=>108, 'css'=>'maxwidth50imp', 'help'=>'DisableStockChangeHelp'),
2049 'batch' =>array('type'=>'varchar(30)', 'label'=>'Batch', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
2050 'role' =>array('type'=>'varchar(10)', 'label'=>'Role', 'enabled'=>1, 'visible'=>-1, 'position'=>145),
2051 'fk_mrp_production' =>array('type'=>'integer', 'label'=>'Fk mrp production', 'enabled'=>1, 'visible'=>-1, 'position'=>150),
2052 'fk_stock_movement' =>array('type'=>'integer', 'label'=>'StockMovement', 'enabled'=>1, 'visible'=>-1, 'position'=>155),
2053 'date_creation' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>160),
2054 'tms' =>array('type'=>'timestamp', 'label'=>'Tms', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>165),
2055 'fk_user_creat' =>array('type'=>'integer', 'label'=>'UserCreation', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>170),
2056 'fk_user_modif' =>array('type'=>'integer', 'label'=>'UserModification', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
2057 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
2058 'fk_default_workstation' =>array('type'=>'integer', 'label'=>'DefaultWorkstation', 'enabled'=>1, 'visible'=>1, 'notnull'=>0, 'position'=>185),
2059 'fk_unit' =>array('type'=>'int', 'label'=>'Unit', 'enabled'=>1, 'visible'=>1, 'notnull'=>0, 'position'=>186)
2060 );
2061
2062 public $rowid;
2063 public $fk_mo;
2064 public $origin_id;
2065 public $origin_type;
2066 public $position;
2067 public $fk_product;
2068 public $fk_warehouse;
2069 public $qty;
2070 public $qty_frozen;
2071 public $disable_stock_change;
2072 public $efficiency;
2073 public $batch;
2074 public $role;
2075 public $fk_mrp_production;
2076 public $fk_stock_movement;
2077 public $date_creation;
2078 public $tms;
2079 public $fk_user_creat;
2080 public $fk_user_modif;
2081 public $import_key;
2082 public $fk_parent_line;
2083 public $fk_unit;
2084
2088 public $fk_default_workstation;
2089
2095 public function __construct(DoliDB $db)
2096 {
2097 global $conf, $langs;
2098
2099 $this->db = $db;
2100
2101 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
2102 $this->fields['rowid']['visible'] = 0;
2103 }
2104 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
2105 $this->fields['entity']['enabled'] = 0;
2106 }
2107
2108 // Unset fields that are disabled
2109 foreach ($this->fields as $key => $val) {
2110 if (isset($val['enabled']) && empty($val['enabled'])) {
2111 unset($this->fields[$key]);
2112 }
2113 }
2114
2115 // Translate some data of arrayofkeyval
2116 if (is_object($langs)) {
2117 foreach ($this->fields as $key => $val) {
2118 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
2119 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
2120 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
2121 }
2122 }
2123 }
2124 }
2125 }
2126
2134 public function create(User $user, $notrigger = false)
2135 {
2136 if (empty($this->qty)) {
2137 $this->error = 'BadValueForQty';
2138 return -1;
2139 }
2140
2141 return $this->createCommon($user, $notrigger);
2142 }
2143
2151 public function fetch($id, $ref = null)
2152 {
2153 $result = $this->fetchCommon($id, $ref);
2154 return $result;
2155 }
2156
2168 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
2169 {
2170 global $conf;
2171
2172 dol_syslog(__METHOD__, LOG_DEBUG);
2173
2174 $records = array();
2175
2176 $sql = 'SELECT ';
2177 $sql .= $this->getFieldList();
2178 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
2179 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2180 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
2181 } else {
2182 $sql .= ' WHERE 1 = 1';
2183 }
2184 // Manage filter
2185 $sqlwhere = array();
2186 if (count($filter) > 0) {
2187 foreach ($filter as $key => $value) {
2188 if ($key == 't.rowid') {
2189 $sqlwhere[] = $key." = ".((int) $value);
2190 } elseif (strpos($key, 'date') !== false) {
2191 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
2192 } elseif ($key == 'customsql') {
2193 $sqlwhere[] = $value;
2194 } else {
2195 $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
2196 }
2197 }
2198 }
2199 if (count($sqlwhere) > 0) {
2200 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
2201 }
2202
2203 if (!empty($sortfield)) {
2204 $sql .= $this->db->order($sortfield, $sortorder);
2205 }
2206 if (!empty($limit)) {
2207 $sql .= $this->db->plimit($limit, $offset);
2208 }
2209
2210 $resql = $this->db->query($sql);
2211 if ($resql) {
2212 $num = $this->db->num_rows($resql);
2213 $i = 0;
2214 while ($i < ($limit ? min($limit, $num) : $num)) {
2215 $obj = $this->db->fetch_object($resql);
2216
2217 $record = new self($this->db);
2218 $record->setVarsFromFetchObj($obj);
2219
2220 $records[$record->id] = $record;
2221
2222 $i++;
2223 }
2224 $this->db->free($resql);
2225
2226 return $records;
2227 } else {
2228 $this->errors[] = 'Error '.$this->db->lasterror();
2229 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2230
2231 return -1;
2232 }
2233 }
2234
2242 public function update(User $user, $notrigger = false)
2243 {
2244 return $this->updateCommon($user, $notrigger);
2245 }
2246
2254 public function delete(User $user, $notrigger = false)
2255 {
2256 return $this->deleteCommon($user, $notrigger);
2257 //return $this->deleteCommon($user, $notrigger, 1);
2258 }
2259}
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Definition security.php:604
$object ref
Definition info.php:79
Class for BOM.
Definition bom.class.php:43
Parent class of all other business classes (invoices, contracts, proposals, orders,...
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
deleteLineCommon(User $user, $idline, $notrigger=false)
Delete a line of object in database.
createCommon(User $user, $notrigger=false)
Create object into database.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
fetch_product()
Load the product with id $this->fk_product into this->product.
updateCommon(User $user, $notrigger=false)
Update object into database.
fetchLinesCommon($morewhere='', $noextrafields=0)
Load object in memory from the database.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage Dolibarr database access.
Class to manage warehouses.
Class for Mo.
Definition mo.class.php:34
__construct(DoliDB $db)
Constructor.
Definition mo.class.php:262
update(User $user, $notrigger=false)
Update object into database.
Definition mo.class.php:657
fetchLinesLinked($role, $lineid=0)
Get list of lines linked to current line for a defined role.
Definition mo.class.php:570
getMoChilds()
Function used to return childs of Mo.
static replaceThirdparty($db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
printOriginLinesList($restrictlist='', $selectedLines=array())
Return HTML table table of source object lines TODO Move this and previous function into output html ...
fetchLines()
Load object lines in memory from the database.
Definition mo.class.php:476
getNextNumRef($prod)
Returns the reference to the following non used MO depending on the active numbering module defined i...
deleteLine(User $user, $idline, $notrigger=false)
Delete a line of object in database.
Definition mo.class.php:901
fetch($id, $ref=null)
Load object in memory from the database.
Definition mo.class.php:459
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
reopen($user, $notrigger=0)
Set back to validated status.
updateProduction(User $user, $notrigger=true)
Update quantities in lines to consume and/or lines to produce.
Definition mo.class.php:811
getMoParent()
Function used to return childs of Mo.
getLinesArray($rolefilter='')
Create an array of lines.
LibStatut($status, $mode=0)
Return the status.
cancel($user, $notrigger=0, $also_cancel_consumed_and_produced_lines=false)
Set cancel status.
setDraft($user, $notrigger=0)
Set draft status.
printOriginLine($line, $var, $restrictlist='', $defaulttpldir='/core/tpl', $selectedLines=array())
Return HTML with a line of table array of source object lines TODO Move this and previous function in...
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
Definition mo.class.php:496
getAllMoChilds($depth=0)
Function used to return all child MOs recursively.
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
validate($user, $notrigger=0)
Validate Mo.
cancelConsumedAndProducedLines($user, $mode=0, $also_delete_lines=false, $notrigger=0)
Cancel consumed and produced lines (movement stocks)
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
getTooltipContentArray($params)
getTooltipContentArray
createProduction(User $user, $notrigger=true)
Erase and update the line to consume and to produce.
Definition mo.class.php:691
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
getLibStatut($mode=0)
Return label of the status.
info($id)
Load the info information in the object.
create(User $user, $notrigger=false)
Create object into database.
Definition mo.class.php:299
countMovements()
Count number of movement with origin of MO.
Definition mo.class.php:622
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition mo.class.php:357
Class MoLine.
create(User $user, $notrigger=false)
Create object into database.
update(User $user, $notrigger=false)
Update object into database.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
__construct(DoliDB $db)
Constructor.
fetch($id, $ref=null)
Load object in memory from the database.
Class to manage stock movements.
Class to manage products or services.
Class to manage Dolibarr users.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.