dolibarr 21.0.0-alpha
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-2024 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
27// Put here all includes required by your class file
28require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
30
31
35class Mo extends CommonObject
36{
40 public $element = 'mo';
41
45 public $table_element = 'mrp_mo';
46
50 public $picto = 'mrp';
51
52
53 const STATUS_DRAFT = 0;
54 const STATUS_VALIDATED = 1; // To produce
55 const STATUS_INPROGRESS = 2;
56 const STATUS_PRODUCED = 3;
57 const STATUS_CANCELED = 9;
58
59
89 public $fields = array(
90 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -2, 'position' => 1, 'notnull' => 1, 'index' => 1, 'comment' => "Id",),
91 'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'position' => 5, 'notnull' => 1, 'default' => '1', 'index' => 1),
92 '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),
93 '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'),
94 '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'),
95 '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'),
96 'qty' => array('type' => 'real', 'label' => 'QtyToProduce', 'enabled' => 1, 'visible' => 1, 'position' => 40, 'notnull' => 1, 'comment' => "Qty to produce", 'css' => 'width75', 'default' => '1', 'isameasure' => 1),
97 '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),
98 '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'),
99 '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'),
100 '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'),
101 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 61, 'notnull' => -1,),
102 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 62, 'notnull' => -1,),
103 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'position' => 500, 'notnull' => 1,),
104 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'position' => 501, 'notnull' => 1,),
105 'date_valid' => array('type' => 'datetime', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -2, 'position' => 502,),
106 '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'),
107 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'position' => 511, 'notnull' => -1, 'csslist' => 'tdoverflowmax100'),
108 'date_start_planned' => array('type' => 'datetime', 'label' => 'DateStartPlannedMo', 'enabled' => 1, 'visible' => 1, 'position' => 55, 'notnull' => -1, 'index' => 1, 'help' => 'KeepEmptyForAsap', 'alwayseditable' => 1, 'csslist' => 'nowraponall'),
109 'date_end_planned' => array('type' => 'datetime', 'label' => 'DateEndPlannedMo', 'enabled' => 1, 'visible' => 1, 'position' => 56, 'notnull' => -1, 'index' => 1, 'alwayseditable' => 1, 'csslist' => 'nowraponall'),
110 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 1000, 'notnull' => -1,),
111 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'visible' => 0, 'position' => 1010),
112 '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')),
113 '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),
114 );
115 public $rowid;
116 public $entity;
117 public $ref;
118
122 public $mrptype;
123 public $label;
124
128 public $qty;
129 public $fk_warehouse;
130 public $fk_soc;
131 public $socid;
132
136 public $note_public;
137
141 public $note_private;
142
146 public $date_valid;
147
148 public $fk_user_creat;
149 public $fk_user_modif;
150 public $import_key;
151 public $status;
152
156 public $fk_product;
157
161 public $product;
162
166 public $date_start_planned;
167
171 public $date_end_planned;
172
176 public $fk_bom;
177
181 public $bom;
182
186 public $fk_project;
187
192 public $oldQty;
193
194
195 // If this object has a subtable with lines
196
200 public $table_element_line = 'mrp_production';
201
205 public $fk_element = 'fk_mo';
206
210 public $class_element_line = 'MoLine';
211
215 protected $childtables = array();
216
220 protected $childtablesoncascade = array('mrp_production');
221
225 public $lines = array();
226
230 public $line = null;
231
235 public $fk_parent_line;
236
240 public $tpl = array();
241
242
248 public function __construct(DoliDB $db)
249 {
250 global $langs;
251
252 $this->db = $db;
253
254 $this->ismultientitymanaged = 1;
255 $this->isextrafieldmanaged = 1;
256
257 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
258 $this->fields['rowid']['visible'] = 0;
259 }
260 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
261 $this->fields['entity']['enabled'] = 0;
262 }
263
264 // Unset fields that are disabled
265 foreach ($this->fields as $key => $val) {
266 if (isset($val['enabled']) && empty($val['enabled'])) {
267 unset($this->fields[$key]);
268 }
269 }
270
271 // Translate some data of arrayofkeyval
272 foreach ($this->fields as $key => $val) {
273 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
274 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
275 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
276 }
277 }
278 }
279 }
280
288 public function create(User $user, $notrigger = 0)
289 {
290 $error = 0;
291 $idcreated = 0;
292
293 // 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
294 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && !getDolGlobalString('ALLOW_USE_KITS_INTO_BOM_AND_MO') && $this->fk_product > 0) {
295 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
296 $tmpproduct = new Product($this->db);
297 $tmpproduct->fetch($this->fk_product);
298 if ($tmpproduct->hasFatherOrChild(1) > 0) {
299 $this->error = 'ErrorAVirtualProductCantBeUsedIntoABomOrMo';
300 $this->errors[] = $this->error;
301 return -1;
302 }
303 }
304
305 $this->db->begin();
306
307 if ($this->fk_bom > 0) {
308 // If there is a known BOM, we force the type of MO to the type of BOM
309 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
310 $tmpbom = new BOM($this->db);
311 $tmpbom->fetch($this->fk_bom);
312
313 $this->mrptype = $tmpbom->bomtype;
314 }
315
316 if (!$error) {
317 $idcreated = $this->createCommon($user, $notrigger);
318 if ($idcreated <= 0) {
319 $error++;
320 }
321 }
322
323 if (!$error) {
324 $result = $this->createProduction($user, $notrigger); // Insert lines from BOM
325 if ($result <= 0) {
326 $error++;
327 }
328 }
329
330 if (!$error) {
331 $this->db->commit();
332 return $idcreated;
333 } else {
334 $this->db->rollback();
335 return -1;
336 }
337 }
338
346 public function createFromClone(User $user, $fromid)
347 {
348 global $langs, $extrafields;
349 $error = 0;
350
351 dol_syslog(__METHOD__, LOG_DEBUG);
352
353 $object = new self($this->db);
354
355 $this->db->begin();
356
357 // Load source object
358 $result = $object->fetchCommon($fromid);
359 if ($result > 0 && !empty($object->table_element_line)) {
360 $object->fetchLines();
361 }
362
363 // get lines so they will be clone
364 //foreach($this->lines as $line)
365 // $line->fetch_optionals();
366
367 // Reset some properties
368 unset($object->id);
369 unset($object->fk_user_creat);
370 unset($object->import_key);
371
372 // We make $object->lines empty to sort it without produced and consumed lines
373 $TLines = $object->lines;
374 $object->lines = array();
375
376 // Remove produced and consumed lines
377 foreach ($TLines as $key => $line) {
378 if (in_array($line->role, array('consumed', 'produced'))) {
379 unset($object->lines[$key]);
380 } else {
381 $object->lines[] = $line;
382 }
383 }
384
385
386 // Clear fields
387 $object->ref = empty($this->fields['ref']['default']) ? "copy_of_".$object->ref : $this->fields['ref']['default'];
388 $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
389 $object->status = self::STATUS_DRAFT;
390 // ...
391 // Clear extrafields that are unique
392 if (is_array($object->array_options) && count($object->array_options) > 0) {
393 $extrafields->fetch_name_optionals_label($this->table_element);
394 foreach ($object->array_options as $key => $option) {
395 $shortkey = preg_replace('/options_/', '', $key);
396 if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
397 //var_dump($key);
398 //var_dump($clonedObj->array_options[$key]); exit;
399 unset($object->array_options[$key]);
400 }
401 }
402 }
403
404 // Create clone
405 $object->context['createfromclone'] = 'createfromclone';
406 $result = $object->createCommon($user);
407 if ($result < 0) {
408 $error++;
409 $this->error = $object->error;
410 $this->errors = $object->errors;
411 }
412
413 if (!$error) {
414 // copy internal contacts
415 if ($this->copy_linked_contact($object, 'internal') < 0) {
416 $error++;
417 }
418 }
419
420 if (!$error) {
421 // copy external contacts if same company
422 if (property_exists($this, 'socid') && $this->socid == $object->socid) {
423 if ($this->copy_linked_contact($object, 'external') < 0) {
424 $error++;
425 }
426 }
427 }
428
429 unset($object->context['createfromclone']);
430
431 // End
432 if (!$error) {
433 $this->db->commit();
434 return $object;
435 } else {
436 $this->db->rollback();
437 return -1;
438 }
439 }
440
448 public function fetch($id, $ref = null)
449 {
450 $result = $this->fetchCommon($id, $ref);
451 if ($result > 0 && !empty($this->table_element_line)) {
452 $this->fetchLines();
453 }
454
455 $this->socid = $this->fk_soc;
456
457 return $result;
458 }
459
465 public function fetchLines()
466 {
467 $this->lines = array();
468
469 $result = $this->fetchLinesCommon();
470 return $result;
471 }
472
473
485 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
486 {
487 dol_syslog(__METHOD__, LOG_DEBUG);
488
489 $records = array();
490
491 $sql = 'SELECT ';
492 $sql .= $this->getFieldList();
493 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
494 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
495 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
496 } else {
497 $sql .= ' WHERE 1 = 1';
498 }
499
500 // Manage filter
501 if (is_array($filter)) {
502 $sqlwhere = array();
503 if (count($filter) > 0) {
504 foreach ($filter as $key => $value) {
505 if ($key == 't.rowid') {
506 $sqlwhere[] = $this->db->sanitize($key)." = ".((int) $value);
507 } elseif (strpos($key, 'date') !== false) {
508 $sqlwhere[] = $this->db->sanitize($key)." = '".$this->db->idate($value)."'";
509 } else {
510 $sqlwhere[] = $this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
511 }
512 }
513 }
514 if (count($sqlwhere) > 0) {
515 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
516 }
517
518 $filter = '';
519 }
520
521 // Manage filter
522 $errormessage = '';
523 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
524 if ($errormessage) {
525 $this->errors[] = $errormessage;
526 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
527 return -1;
528 }
529
530 if (!empty($sortfield)) {
531 $sql .= $this->db->order($sortfield, $sortorder);
532 }
533 if (!empty($limit)) {
534 $sql .= $this->db->plimit($limit, $offset);
535 }
536
537 $resql = $this->db->query($sql);
538 if ($resql) {
539 $num = $this->db->num_rows($resql);
540 $i = 0;
541 while ($i < min($limit, $num)) {
542 $obj = $this->db->fetch_object($resql);
543
544 $record = new self($this->db);
545 $record->setVarsFromFetchObj($obj);
546
547 $records[$record->id] = $record;
548
549 $i++;
550 }
551 $this->db->free($resql);
552
553 return $records;
554 } else {
555 $this->errors[] = 'Error '.$this->db->lasterror();
556 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
557
558 return -1;
559 }
560 }
561
569 public function fetchLinesLinked($role, $lineid = 0)
570 {
571 $resarray = array();
572 $mostatic = new MoLine($this->db);
573
574 $sql = 'SELECT ';
575 $sql .= $mostatic->getFieldList();
576 $sql .= ' FROM '.MAIN_DB_PREFIX.$mostatic->table_element.' as t';
577 $sql .= " WHERE t.role = '".$this->db->escape($role)."'";
578 if ($lineid > 0) {
579 $sql .= ' AND t.fk_mrp_production = '.((int) $lineid);
580 } else {
581 $sql .= 'AND t.fk_mo = '.((int) $this->id);
582 }
583
584 $resql = $this->db->query($sql);
585 if ($resql) {
586 $num = $this->db->num_rows($resql);
587
588 $i = 0;
589 while ($i < $num) {
590 $obj = $this->db->fetch_object($resql);
591 if ($obj) {
592 $resarray[] = array(
593 'rowid' => $obj->rowid,
594 'date' => $this->db->jdate($obj->date_creation),
595 'qty' => $obj->qty,
596 'role' => $obj->role,
597 'fk_product' => $obj->fk_product,
598 'fk_warehouse' => $obj->fk_warehouse,
599 'batch' => $obj->batch,
600 'fk_stock_movement' => $obj->fk_stock_movement,
601 'fk_unit' => $obj->fk_unit
602 );
603 }
604
605 $i++;
606 }
607
608 return $resarray;
609 } else {
610 $this->error = $this->db->lasterror();
611 return array();
612 }
613 }
614
615
621 public function countMovements()
622 {
623 $result = 0;
624
625 $sql = 'SELECT COUNT(rowid) as nb FROM '.MAIN_DB_PREFIX.'stock_mouvement as sm';
626 $sql .= " WHERE sm.origintype = 'mo' and sm.fk_origin = ".((int) $this->id);
627
628 $resql = $this->db->query($sql);
629 if ($resql) {
630 $num = $this->db->num_rows($resql);
631
632 $i = 0;
633 while ($i < $num) {
634 $obj = $this->db->fetch_object($resql);
635 if ($obj) {
636 $result = $obj->nb;
637 }
638
639 $i++;
640 }
641 } else {
642 $this->error = $this->db->lasterror();
643 }
644
645 return $result;
646 }
647
648
656 public function update(User $user, $notrigger = 0)
657 {
658 $error = 0;
659
660 $this->db->begin();
661
662 $result = $this->updateCommon($user, $notrigger);
663 if ($result <= 0) {
664 $error++;
665 }
666
667 // Update the lines (the qty) to consume or to produce
668 $result = $this->updateProduction($user, $notrigger);
669 if ($result <= 0) {
670 $error++;
671 }
672
673 if (!$error) {
674 $this->db->commit();
675 return 1;
676 } else {
677 $this->db->rollback();
678 return -1;
679 }
680 }
681
682
690 public function createProduction(User $user, $notrigger = 0)
691 {
692 $error = 0;
693 $role = "";
694
695 if ($this->status != self::STATUS_DRAFT) {
696 return -1;
697 }
698
699 $this->db->begin();
700
701 // Insert lines in mrp_production table from BOM data
702 if (!$error) {
703 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'mrp_production WHERE fk_mo = '.((int) $this->id);
704 $this->db->query($sql);
705
706 $moline = new MoLine($this->db);
707
708 // Line to produce
709 $moline->fk_mo = $this->id;
710 $moline->qty = $this->qty;
711 $moline->fk_product = $this->fk_product;
712 $moline->position = 1;
713 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
714 $tmpproduct = new Product($this->db);
715 $tmpproduct->fetch($this->fk_product);
716 $moline->fk_unit = $tmpproduct->fk_unit;
717
718 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to produce.
719 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
720 $bom = new BOM($this->db);
721 $bom->fetch($this->fk_bom);
722 if ($bom->bomtype == 1) {
723 $role = 'toproduce';
724 $moline->role = 'toconsume';
725 } else {
726 $role = 'toconsume';
727 $moline->role = 'toproduce';
728 }
729 } else {
730 if ($this->mrptype == 1) {
731 $moline->role = 'toconsume';
732 } else {
733 $moline->role = 'toproduce';
734 }
735 }
736
737 $resultline = $moline->create($user, false); // Never use triggers here
738 if ($resultline <= 0) {
739 $error++;
740 $this->error = $moline->error;
741 $this->errors = $moline->errors;
742 }
743
744 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to consume.
745 if ($bom->id > 0) {
746 // Lines to consume
747 if (!$error) {
748 foreach ($bom->lines as $line) {
749 $moline = new MoLine($this->db);
750
751 $moline->fk_mo = $this->id;
752 $moline->origin_id = $line->id;
753 $moline->origin_type = 'bomline';
754 if (!empty($line->fk_unit)) {
755 $moline->fk_unit = $line->fk_unit;
756 }
757 if ($line->qty_frozen) {
758 $moline->qty = $line->qty; // Qty to consume does not depends on quantity to produce
759 } else {
760 $moline->qty = (float) 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
761 }
762 if ($moline->qty <= 0) {
763 $error++;
764 $this->error = "BadValueForquantityToConsume";
765 break;
766 } else {
767 $moline->fk_product = $line->fk_product;
768 $moline->role = $role;
769 $moline->position = $line->position;
770 $moline->qty_frozen = $line->qty_frozen;
771 $moline->disable_stock_change = $line->disable_stock_change;
772 if (!empty($line->fk_default_workstation)) {
773 $moline->fk_default_workstation = $line->fk_default_workstation;
774 }
775
776 $resultline = $moline->create($user, false); // Never use triggers here
777 if ($resultline <= 0) {
778 $error++;
779 $this->error = $moline->error;
780 $this->errors = $moline->errors;
781 dol_print_error($this->db, $moline->error, $moline->errors);
782 break;
783 }
784 }
785 }
786 }
787 }
788 }
789 }
790
791 if (!$error) {
792 $this->db->commit();
793 return 1;
794 } else {
795 $this->db->rollback();
796 return -1;
797 }
798 }
799
807 public function updateProduction(User $user, $notrigger = 0)
808 {
809 $error = 0;
810
811 if ($this->status != self::STATUS_DRAFT) {
812 return 1;
813 }
814
815 $this->db->begin();
816
817 $oldQty = $this->oldQty;
818 $newQty = $this->qty;
819 if ($newQty != $oldQty && !empty($this->oldQty)) {
820 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "mrp_production WHERE fk_mo = " . (int) $this->id;
821 $resql = $this->db->query($sql);
822 if ($resql) {
823 while ($obj = $this->db->fetch_object($resql)) {
824 $moLine = new MoLine($this->db);
825 $res = $moLine->fetch($obj->rowid);
826 if (!$res) {
827 $error++;
828 }
829
830 if ($moLine->role == 'toconsume' || $moLine->role == 'toproduce') {
831 if (empty($moLine->qty_frozen)) {
832 $qty = $newQty * $moLine->qty / $oldQty;
833 $moLine->qty = (float) price2num($qty, 'MS');
834 $res = $moLine->update($user);
835 if (!$res) {
836 $error++;
837 }
838 }
839 }
840 }
841 }
842 }
843 if (!$error) {
844 $this->db->commit();
845 return 1;
846 } else {
847 $this->db->rollback();
848 return -1;
849 }
850 }
851
852
861 public function delete(User $user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
862 {
863 $error = 0;
864 $this->db->begin();
865
866 if ($also_cancel_consumed_and_produced_lines) {
867 $result = $this->cancelConsumedAndProducedLines($user, 0, false, $notrigger);
868 if ($result < 0) {
869 $error++;
870 }
871 }
872
873 if (!$error) {
874 $result = $this->deleteCommon($user, $notrigger);
875 if ($result < 0) {
876 $error++;
877 }
878 }
879
880 if ($error) {
881 $this->db->rollback();
882 return -1;
883 } else {
884 $this->db->commit();
885 return 1;
886 }
887 }
888
898 public function deleteLine(User $user, $idline, $notrigger = 0, $fk_movement = 0)
899 {
900 global $langs;
901 $langs->loadLangs(array('stocks', 'mrp'));
902
903 if ($this->status < 0) {
904 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
905 return -2;
906 }
907 $productstatic = new Product($this->db);
908
909 $arrayoflines = $this->fetchLinesLinked('consumed', $idline); // Get lines consumed under the one to delete
910
911 $result = 0;
912
913 $this->db->begin();
914
915 if (!empty($arrayoflines)) {
916 // If there is child lines
917 $stockmove = new MouvementStock($this->db);
918 $stockmove->setOrigin($this->element, $this->id);
919
920 if (!empty($fk_movement)) {
921 // The fk_movement was not recorded so we try to guess the product and quantity to restore.
922 $moline = new MoLine($this->db);
923 $TArrayMoLine = $moline->fetchAll('', '', 1, 0, '(fk_stock_movement:=:'.((int) $fk_movement).')');
924 $moline = array_shift($TArrayMoLine);
925
926 $movement = new MouvementStock($this->db);
927 $movement->fetch($fk_movement);
928 $productstatic->fetch($movement->product_id);
929 $qtytoprocess = $movement->qty;
930
931 // Reverse stock movement
932 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
933 $codemovementCancel = $langs->trans("StockIncrease");
934
935 if (($qtytoprocess >= 0)) {
936 $idstockmove = $stockmove->reception($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, '', '', $movement->batch, dol_now(), 0, $codemovementCancel);
937 } else {
938 $idstockmove = $stockmove->livraison($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $movement->batch, 0, $codemovementCancel);
939 }
940 if ($idstockmove < 0) {
941 $this->error++;
942 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
943 } else {
944 $result = $moline->delete($user, $notrigger);
945 }
946 } else {
947 // Loop on each child lines
948 foreach ($arrayoflines as $key => $arrayofline) {
949 $lineDetails = $arrayoflines[$key];
950 $productstatic->fetch($lineDetails['fk_product']);
951 $qtytoprocess = $lineDetails['qty'];
952
953 // Reverse stock movement
954 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
955 $codemovementCancel = $langs->trans("StockIncrease");
956
957
958 if ($qtytoprocess >= 0) {
959 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
960 } else {
961 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
962 }
963 if ($idstockmove < 0) {
964 $this->error++;
965 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
966 } else {
967 $moline = new MoLine($this->db);
968 $moline->fetch($lineDetails['rowid']);
969
970 $resdel = $moline->delete($user, $notrigger);
971 if ($resdel < 0) {
972 $this->error++;
973 setEventMessages($moline->error, $moline->errors, 'errors');
974 }
975 }
976 }
977
978 if (empty($this->error)) {
979 $result = $this->deleteLineCommon($user, $idline, $notrigger);
980 }
981 }
982 } else {
983 // No child lines
984 $result = $this->deleteLineCommon($user, $idline, $notrigger);
985 }
986
987 if (!empty($this->error) || $result <= 0) {
988 $this->db->rollback();
989 } else {
990 $this->db->commit();
991 }
992
993 return $result;
994 }
995
996
1004 public function getNextNumRef($prod)
1005 {
1006 global $langs, $conf;
1007 $langs->load("mrp");
1008
1009 if (getDolGlobalString('MRP_MO_ADDON')) {
1010 $mybool = false;
1011
1012 $file = getDolGlobalString('MRP_MO_ADDON') . ".php";
1013 $classname = getDolGlobalString('MRP_MO_ADDON');
1014
1015 // Include file with class
1016 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1017 foreach ($dirmodels as $reldir) {
1018 $dir = dol_buildpath($reldir."core/modules/mrp/");
1019
1020 // Load file with numbering class (if found)
1021 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1022 }
1023
1024 if ($mybool === false) {
1025 dol_print_error(null, "Failed to include file ".$file);
1026 return '';
1027 }
1028
1029 $obj = new $classname();
1030 $numref = $obj->getNextValue($prod, $this);
1031
1032 if ($numref != "") {
1033 return $numref;
1034 } else {
1035 $this->error = $obj->error;
1036 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1037 return "";
1038 }
1039 } else {
1040 print $langs->trans("Error")." ".$langs->trans("Error_MRP_MO_ADDON_NotDefined");
1041 return "";
1042 }
1043 }
1044
1052 public function validate($user, $notrigger = 0)
1053 {
1054 global $conf;
1055
1056 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1057
1058 $error = 0;
1059
1060 // Protection
1061 if ($this->status == self::STATUS_VALIDATED) {
1062 dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING);
1063 return 0;
1064 }
1065
1066 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->create))
1067 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->mrp_advance->validate))))
1068 {
1069 $this->error='NotEnoughPermissions';
1070 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
1071 return -1;
1072 }*/
1073
1074 $now = dol_now();
1075
1076 $this->db->begin();
1077
1078 // Define new ref
1079 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1080 $this->fetch_product();
1081 $num = $this->getNextNumRef($this->product);
1082 } else {
1083 $num = $this->ref;
1084 }
1085 $this->newref = $num;
1086
1087 // Validate
1088 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1089 $sql .= " SET ref = '".$this->db->escape($num)."',";
1090 $sql .= " status = ".self::STATUS_VALIDATED.",";
1091 $sql .= " date_valid='".$this->db->idate($now)."',";
1092 $sql .= " fk_user_valid = ".$user->id;
1093 $sql .= " WHERE rowid = ".((int) $this->id);
1094
1095 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
1096 $resql = $this->db->query($sql);
1097 if (!$resql) {
1098 dol_print_error($this->db);
1099 $this->error = $this->db->lasterror();
1100 $error++;
1101 }
1102
1103 if (!$error && !$notrigger) {
1104 // Call trigger
1105 $result = $this->call_trigger('MRP_MO_VALIDATE', $user);
1106 if ($result < 0) {
1107 $error++;
1108 }
1109 // End call triggers
1110 }
1111
1112 if (!$error) {
1113 $this->oldref = $this->ref;
1114
1115 // Rename directory if dir was a temporary ref
1116 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1117 // Now we rename also files into index
1118 $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)."'";
1119 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'mrp/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1120 $resql = $this->db->query($sql);
1121 if (!$resql) {
1122 $error++;
1123 $this->error = $this->db->lasterror();
1124 }
1125 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'mrp/".$this->db->escape($this->newref)."'";
1126 $sql .= " WHERE filepath = 'mrp/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1127 $resql = $this->db->query($sql);
1128 if (!$resql) {
1129 $error++;
1130 $this->error = $this->db->lasterror();
1131 }
1132
1133 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1134 $oldref = dol_sanitizeFileName($this->ref);
1135 $newref = dol_sanitizeFileName($num);
1136 $dirsource = $conf->mrp->dir_output.'/'.$oldref;
1137 $dirdest = $conf->mrp->dir_output.'/'.$newref;
1138 if (!$error && file_exists($dirsource)) {
1139 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
1140
1141 if (@rename($dirsource, $dirdest)) {
1142 dol_syslog("Rename ok");
1143 // Rename docs starting with $oldref with $newref
1144 $listoffiles = dol_dir_list($conf->mrp->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1145 foreach ($listoffiles as $fileentry) {
1146 $dirsource = $fileentry['name'];
1147 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1148 $dirsource = $fileentry['path'].'/'.$dirsource;
1149 $dirdest = $fileentry['path'].'/'.$dirdest;
1150 @rename($dirsource, $dirdest);
1151 }
1152 }
1153 }
1154 }
1155 }
1156
1157 // Set new ref and current status
1158 if (!$error) {
1159 $this->ref = $num;
1160 $this->status = self::STATUS_VALIDATED;
1161 }
1162
1163 if (!$error) {
1164 $this->db->commit();
1165 return 1;
1166 } else {
1167 $this->db->rollback();
1168 return -1;
1169 }
1170 }
1171
1179 public function setDraft($user, $notrigger = 0)
1180 {
1181 // Protection
1182 if ($this->status <= self::STATUS_DRAFT) {
1183 return 0;
1184 }
1185
1186 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1187 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1188 {
1189 $this->error='Permission denied';
1190 return -1;
1191 }*/
1192
1193 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'MRP_MO_UNVALIDATE');
1194 }
1195
1204 public function cancel($user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
1205 {
1206 // Protection
1207 if ($this->status != self::STATUS_VALIDATED && $this->status != self::STATUS_INPROGRESS) {
1208 return 0;
1209 }
1210
1211 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1212 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1213 {
1214 $this->error='Permission denied';
1215 return -1;
1216 }*/
1217
1218 $error = 0;
1219 $this->db->begin();
1220
1221 if ($also_cancel_consumed_and_produced_lines) {
1222 $result = $this->cancelConsumedAndProducedLines($user, 0, true, $notrigger);
1223 if ($result < 0) {
1224 $error++;
1225 }
1226 }
1227
1228 if (!$error) {
1229 $result = $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'MRP_MO_CANCEL');
1230 if ($result < 0) {
1231 $error++;
1232 }
1233 }
1234
1235 if ($error) {
1236 $this->db->rollback();
1237 return -1;
1238 } else {
1239 $this->db->commit();
1240 return 1;
1241 }
1242 }
1243
1251 public function reopen($user, $notrigger = 0)
1252 {
1253 // Protection
1254 if ($this->status != self::STATUS_PRODUCED && $this->status != self::STATUS_CANCELED) {
1255 return 0;
1256 }
1257
1258 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1259 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1260 {
1261 $this->error='Permission denied';
1262 return -1;
1263 }*/
1264
1265 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'MRP_MO_REOPEN');
1266 }
1267
1277 public function cancelConsumedAndProducedLines($user, $mode = 0, $also_delete_lines = false, $notrigger = 0)
1278 {
1279 global $langs;
1280
1281 if (!isModEnabled('stock')) {
1282 return 1;
1283 }
1284
1285 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1286 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php';
1287 $error = 0;
1288 $langs->load('stocks');
1289
1290 $this->db->begin();
1291
1292 // Cancel consumed lines
1293 if (empty($mode) || $mode == 1) {
1294 $arrayoflines = $this->fetchLinesLinked('consumed');
1295 if (!empty($arrayoflines)) {
1296 foreach ($arrayoflines as $key => $lineDetails) {
1297 $productstatic = new Product($this->db);
1298 $productstatic->fetch($lineDetails['fk_product']);
1299 $qtytoprocess = $lineDetails['qty'];
1300
1301 // Reverse stock movement
1302 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1303 $codemovementCancel = $langs->trans("StockIncrease");
1304
1305 $stockmove = new MouvementStock($this->db);
1306 $stockmove->setOrigin($this->element, $this->id);
1307 if ($qtytoprocess >= 0) {
1308 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1309 } else {
1310 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1311 }
1312 if ($idstockmove < 0) {
1313 $this->error = $stockmove->error;
1314 $this->errors = $stockmove->errors;
1315 $error++;
1316 break;
1317 }
1318
1319 if ($also_delete_lines) {
1320 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1321 if ($result < 0) {
1322 $error++;
1323 break;
1324 }
1325 }
1326 }
1327 }
1328 }
1329
1330 // Cancel produced lines
1331 if (empty($mode) || $mode == 2) {
1332 $arrayoflines = $this->fetchLinesLinked('produced');
1333 if (!empty($arrayoflines)) {
1334 foreach ($arrayoflines as $key => $lineDetails) {
1335 $productstatic = new Product($this->db);
1336 $productstatic->fetch($lineDetails['fk_product']);
1337 $qtytoprocess = $lineDetails['qty'];
1338
1339 // Reverse stock movement
1340 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1341 $codemovementCancel = $langs->trans("StockDecrease");
1342
1343 $stockmove = new MouvementStock($this->db);
1344 $stockmove->setOrigin($this->element, $this->id);
1345 if ($qtytoprocess >= 0) {
1346 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1347 } else {
1348 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1349 }
1350 if ($idstockmove < 0) {
1351 $this->error = $stockmove->error;
1352 $this->errors = $stockmove->errors;
1353 $error++;
1354 break;
1355 }
1356
1357 if ($also_delete_lines) {
1358 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1359 if ($result < 0) {
1360 $error++;
1361 break;
1362 }
1363 }
1364 }
1365 }
1366 }
1367
1368 if ($error) {
1369 $this->db->rollback();
1370 return -1;
1371 } else {
1372 $this->db->commit();
1373 return 1;
1374 }
1375 }
1376
1384 public function getTooltipContentArray($params)
1385 {
1386 global $langs;
1387
1388 $langs->loadLangs(['mrp', 'products']);
1389 $nofetch = isset($params['nofetch']) ? true : false;
1390
1391 $datas = [];
1392
1393 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ManufacturingOrder").'</u>';
1394 if (isset($this->status)) {
1395 $datas['picto'] .= ' '.$this->getLibStatut(5);
1396 }
1397 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1398 if (isset($this->label)) {
1399 $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1400 }
1401 if (isset($this->mrptype)) {
1402 $datas['type'] = '<br><b>'.$langs->trans('Type').':</b> '.$this->fields['mrptype']['arrayofkeyval'][$this->mrptype];
1403 }
1404 if (isset($this->qty)) {
1405 $datas['qty'] = '<br><b>'.$langs->trans('QtyToProduce').':</b> '.$this->qty;
1406 }
1407 if (!$nofetch && isset($this->fk_product)) {
1408 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1409 $product = new Product($this->db);
1410 $product->fetch($this->fk_product);
1411 $datas['product'] = '<br><b>'.$langs->trans('Product').':</b> '.$product->getNomUrl(1, '', 0, -1, 1);
1412 }
1413 if (!$nofetch && isset($this->fk_warehouse)) {
1414 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
1415 $warehouse = new Entrepot($this->db);
1416 $warehouse->fetch($this->fk_warehouse);
1417 $datas['warehouse'] = '<br><b>'.$langs->trans('WarehouseForProduction').':</b> '.$warehouse->getNomUrl(1, '', 0, 1);
1418 }
1419
1420 return $datas;
1421 }
1422
1433 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1434 {
1435 global $conf, $langs, $action, $hookmanager;
1436
1437 if (!empty($conf->dol_no_mouse_hover)) {
1438 $notooltip = 1; // Force disable tooltips
1439 }
1440
1441 $result = '';
1442 $params = [
1443 'id' => $this->id,
1444 'objecttype' => $this->element,
1445 'option' => $option,
1446 'nofetch' => 1,
1447 ];
1448 $classfortooltip = 'classfortooltip';
1449 $dataparams = '';
1450 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1451 $classfortooltip = 'classforajaxtooltip';
1452 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1453 $label = '';
1454 } else {
1455 $label = implode($this->getTooltipContentArray($params));
1456 }
1457
1458 $url = DOL_URL_ROOT.'/mrp/mo_card.php?id='.$this->id;
1459 if ($option == 'production') {
1460 $url = DOL_URL_ROOT.'/mrp/mo_production.php?id='.$this->id;
1461 }
1462
1463 if ($option != 'nolink') {
1464 // Add param to save lastsearch_values or not
1465 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1466 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1467 $add_save_lastsearch_values = 1;
1468 }
1469 if ($add_save_lastsearch_values) {
1470 $url .= '&save_lastsearch_values=1';
1471 }
1472 }
1473
1474 $linkclose = '';
1475 if (empty($notooltip)) {
1476 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1477 $label = $langs->trans("ShowMo");
1478 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1479 }
1480 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1481 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1482 } else {
1483 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1484 }
1485
1486 $linkstart = '<a href="'.$url.'"';
1487 $linkstart .= $linkclose.'>';
1488 $linkend = '</a>';
1489
1490 $result .= $linkstart;
1491 if ($withpicto) {
1492 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
1493 }
1494 if ($withpicto != 2) {
1495 $result .= $this->ref;
1496 }
1497 $result .= $linkend;
1498 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1499
1500 $hookmanager->initHooks(array('modao'));
1501 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1502 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1503 if ($reshook > 0) {
1504 $result = $hookmanager->resPrint;
1505 } else {
1506 $result .= $hookmanager->resPrint;
1507 }
1508
1509 return $result;
1510 }
1511
1518 public function getLibStatut($mode = 0)
1519 {
1520 return $this->LibStatut($this->status, $mode);
1521 }
1522
1523 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1531 public function LibStatut($status, $mode = 0)
1532 {
1533 // phpcs:enable
1534 if (empty($this->labelStatus)) {
1535 global $langs;
1536 //$langs->load("mrp");
1537 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1538 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('ValidatedToProduce');
1539 $this->labelStatus[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1540 $this->labelStatus[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1541 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1542
1543 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1544 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
1545 $this->labelStatusShort[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1546 $this->labelStatusShort[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1547 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1548 }
1549
1550 $statusType = 'status'.$status;
1551 if ($status == self::STATUS_VALIDATED) {
1552 $statusType = 'status1';
1553 }
1554 if ($status == self::STATUS_INPROGRESS) {
1555 $statusType = 'status4';
1556 }
1557 if ($status == self::STATUS_PRODUCED) {
1558 $statusType = 'status6';
1559 }
1560 if ($status == self::STATUS_CANCELED) {
1561 $statusType = 'status9';
1562 }
1563
1564 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1565 }
1566
1573 public function info($id)
1574 {
1575 $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1576 $sql .= ' fk_user_creat, fk_user_modif';
1577 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1578 $sql .= ' WHERE t.rowid = '.((int) $id);
1579 $result = $this->db->query($sql);
1580 if ($result) {
1581 if ($this->db->num_rows($result)) {
1582 $obj = $this->db->fetch_object($result);
1583
1584 $this->id = $obj->rowid;
1585
1586 $this->user_creation_id = $obj->fk_user_creat;
1587 $this->user_modification_id = $obj->fk_user_modif;
1588 $this->date_creation = $this->db->jdate($obj->datec);
1589 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1590 }
1591
1592 $this->db->free($result);
1593 } else {
1594 dol_print_error($this->db);
1595 }
1596 }
1597
1604 public function initAsSpecimen()
1605 {
1606 $ret = $this->initAsSpecimenCommon();
1607
1608 $this->lines = array();
1609
1610 return $ret;
1611 }
1612
1619 public function getLinesArray($rolefilter = '')
1620 {
1621 $this->lines = array();
1622
1623 $objectline = new MoLine($this->db);
1624
1625 $filter = '(fk_mo:=:'.((int) $this->id).')';
1626 if (!empty($rolefilter)) {
1627 $filter .= " AND (role:=:'".$this->db->escape($rolefilter)."')";
1628 }
1629 $result = $objectline->fetchAll('ASC', 'position', 0, 0, $filter);
1630
1631 if (is_numeric($result)) {
1632 $this->error = $objectline->error;
1633 $this->errors = $objectline->errors;
1634 return $result;
1635 } else {
1636 $this->lines = $result;
1637 return $this->lines;
1638 }
1639 }
1640
1652 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1653 {
1654 global $langs;
1655
1656 $langs->load("mrp");
1657
1658 if (!dol_strlen($modele)) {
1659 //$modele = 'standard';
1660 $modele = ''; // Remove this once a pdf_standard.php exists.
1661
1662 if ($this->model_pdf) {
1663 $modele = $this->model_pdf;
1664 } elseif (getDolGlobalString('MRP_MO_ADDON_PDF')) {
1665 $modele = getDolGlobalString('MRP_MO_ADDON_PDF');
1666 }
1667 }
1668
1669 $modelpath = "core/modules/mrp/doc/";
1670
1671 if (empty($modele)) {
1672 return 1; // Remove this once a pdf_standard.php exists.
1673 }
1674
1675 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1676 }
1677
1688 public function printOriginLinesList($restrictlist = '', $selectedLines = array())
1689 {
1690 global $langs, $hookmanager, $form, $action;
1691
1692 $langs->load('stocks');
1693 $text_stock_options = $langs->trans("RealStockDesc").'<br>';
1694 $text_stock_options .= $langs->trans("RealStockWillAutomaticallyWhen").'<br>';
1695 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT') || getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE') ? '- '.$langs->trans("DeStockOnShipment").'<br>' : '');
1696 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_VALIDATE_ORDER') ? '- '.$langs->trans("DeStockOnValidateOrder").'<br>' : '');
1697 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_BILL') ? '- '.$langs->trans("DeStockOnBill").'<br>' : '');
1698 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL') ? '- '.$langs->trans("ReStockOnBill").'<br>' : '');
1699 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER') ? '- '.$langs->trans("ReStockOnValidateOrder").'<br>' : '');
1700 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') ? '- '.$langs->trans("ReStockOnDispatchOrder").'<br>' : '');
1701 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION') || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE') ? '- '.$langs->trans("StockOnReception").'<br>' : '');
1702
1703 print '<tr class="liste_titre">';
1704 // Product or sub-bom
1705 print '<td class="linecoldescription">'.$langs->trans('Ref');
1706 if (getDolGlobalString('BOM_SUB_BOM')) {
1707 print ' &nbsp; <a id="show_all" href="#">'.img_picto('', 'folder-open', 'class="paddingright"').$langs->trans("ExpandAll").'</a>&nbsp;&nbsp;';
1708 print '<a id="hide_all" href="#">'.img_picto('', 'folder', 'class="paddingright"').$langs->trans("UndoExpandAll").'</a>&nbsp;';
1709 }
1710 print '</td>';
1711 // Qty
1712 print '<td class="right">'.$langs->trans('Qty');
1713 if ($this->bom->bomtype == 0) {
1714 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityOf", $this->bom->qty).')</span>';
1715 } else {
1716 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityToConsumeOf", $this->bom->qty).')</span>';
1717 }
1718 // Unit
1719 print '<td class="right">'.$langs->trans('Unit');
1720
1721 print '</td>';
1722 print '<td class="center">'.$form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1).'</td>';
1723 print '<td class="center">'.$form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc")).'</td>';
1724 print '<td class="center">'.$langs->trans('QtyFrozen').'</td>';
1725 print '<td class="center">'.$langs->trans('DisableStockChange').'</td>';
1726 print '<td class="center">'.$langs->trans('MoChildGenerate').'</td>';
1727 //print '<td class="center">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
1728 //print '<td class="center"></td>';
1729 print '</tr>';
1730 $i = 0;
1731
1732 if (!empty($this->lines)) {
1733 foreach ($this->lines as $line) {
1734 $reshook = 0;
1735 if (is_object($hookmanager)) {
1736 $parameters = array('line' => $line, 'i' => $i, 'restrictlist' => $restrictlist, 'selectedLines' => $selectedLines);
1737 if (!empty($line->fk_parent_line)) {
1738 $parameters['fk_parent_line'] = $line->fk_parent_line;
1739 }
1740 $reshook = $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1741 }
1742 if (empty($reshook)) {
1743 $this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
1744 }
1745
1746 $i++;
1747 }
1748 }
1749 }
1750
1751
1765 public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
1766 {
1767 $productstatic = new Product($this->db);
1768
1769 $this->tpl['id'] = $line->id;
1770
1771 $this->tpl['label'] = '';
1772 if (!empty($line->fk_product) && $line->fk_product > 0) {
1773 $productstatic->fetch($line->fk_product);
1774 $productstatic->load_virtual_stock();
1775 $this->tpl['label'] .= $productstatic->getNomUrl(1);
1776 //$this->tpl['label'].= ' - '.$productstatic->label;
1777 } else {
1778 // If origin MO line is not a product, but another MO
1779 // TODO
1780 }
1781
1782 $this->tpl['qty_bom'] = 1;
1783 if (is_object($this->bom) && $this->bom->qty > 1) {
1784 $this->tpl['qty_bom'] = $this->bom->qty;
1785 }
1786
1787 $this->tpl['stock'] = $productstatic->stock_reel;
1788 $this->tpl['seuil_stock_alerte'] = $productstatic->seuil_stock_alerte;
1789 $this->tpl['virtual_stock'] = $productstatic->stock_theorique;
1790 $this->tpl['qty'] = $line->qty;
1791 $this->tpl['fk_unit'] = $line->fk_unit;
1792 $this->tpl['qty_frozen'] = $line->qty_frozen;
1793 $this->tpl['disable_stock_change'] = $line->disable_stock_change;
1794 $this->tpl['efficiency'] = $line->efficiency;
1795
1796 global $conf; // used into template
1797 $res = include DOL_DOCUMENT_ROOT.'/mrp/tpl/originproductline.tpl.php';
1798 }
1799
1808 public static function replaceThirdparty($db, $origin_id, $dest_id)
1809 {
1810 $tables = array('mrp_mo');
1811
1812 return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1813 }
1814
1815
1821 public function getMoChilds()
1822 {
1823 $TMoChilds = array();
1824 $error = 0;
1825
1826 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_mo as mo_child";
1827 $sql .= " WHERE fk_parent_line IN ";
1828 $sql .= " (SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_production as line_parent";
1829 $sql .= " WHERE fk_mo=".((int) $this->id).")";
1830
1831 $resql = $this->db->query($sql);
1832
1833 if ($resql) {
1834 if ($this->db->num_rows($resql) > 0) {
1835 while ($obj = $this->db->fetch_object($resql)) {
1836 $MoChild = new Mo($this->db);
1837 $res = $MoChild->fetch($obj->rowid);
1838 if ($res > 0) {
1839 $TMoChilds[$MoChild->id] = $MoChild;
1840 } else {
1841 $error++;
1842 }
1843 }
1844 }
1845 } else {
1846 $error++;
1847 }
1848
1849 if ($error) {
1850 return -1;
1851 } else {
1852 return $TMoChilds;
1853 }
1854 }
1855
1862 public function getAllMoChilds($depth = 0)
1863 {
1864 if ($depth > 1000) {
1865 return -1;
1866 }
1867
1868 $TMoChilds = array();
1869 $error = 0;
1870
1871 $childMoList = $this->getMoChilds();
1872
1873 if ($childMoList == -1) {
1874 return -1;
1875 }
1876
1877 foreach ($childMoList as $childMo) {
1878 $TMoChilds[$childMo->id] = $childMo;
1879 }
1880
1881 foreach ($childMoList as $childMo) {
1882 $childMoChildren = $childMo->getAllMoChilds($depth + 1);
1883
1884 if ($childMoChildren == -1) {
1885 $error++;
1886 } else {
1887 foreach ($childMoChildren as $child) {
1888 $TMoChilds[$child->id] = $child;
1889 }
1890 }
1891 }
1892
1893 if ($error) {
1894 return -1;
1895 } else {
1896 return $TMoChilds;
1897 }
1898 }
1899
1900
1901
1907 public function getMoParent()
1908 {
1909 $MoParent = new Mo($this->db);
1910 $error = 0;
1911
1912 $sql = "SELECT lineparent.fk_mo as id_moparent FROM ".MAIN_DB_PREFIX."mrp_mo as mo";
1913 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."mrp_production lineparent ON mo.fk_parent_line = lineparent.rowid";
1914 $sql .= " WHERE mo.rowid = ".((int) $this->id);
1915
1916 $resql = $this->db->query($sql);
1917
1918 if ($resql) {
1919 if ($this->db->num_rows($resql) > 0) {
1920 $obj = $this->db->fetch_object($resql);
1921 $res = $MoParent->fetch($obj->id_moparent);
1922 if ($res < 0) {
1923 $error++;
1924 }
1925 } else {
1926 return 0;
1927 }
1928 } else {
1929 $error++;
1930 }
1931
1932 if ($error) {
1933 return -1;
1934 } else {
1935 return $MoParent;
1936 }
1937 }
1938
1946 public function getKanbanView($option = '', $arraydata = null)
1947 {
1948 global $langs;
1949
1950 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1951
1952 $return = '<div class="box-flex-item box-flex-grow-zero">';
1953 $return .= '<div class="info-box info-box-sm">';
1954 $return .= '<span class="info-box-icon bg-infobox-action">';
1955 $return .= img_picto('', $this->picto);
1956 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
1957 $return .= '</span>';
1958 $return .= '<div class="info-box-content">';
1959 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
1960 if ($selected >= 0) {
1961 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1962 }
1963 if (!empty($arraydata['bom'])) {
1964 $return .= '<br><span class="info-box-label">'.$arraydata['bom']->getNomUrl(1).'</span>';
1965 }
1966 if (!empty($arraydata['product'])) {
1967 $return .= '<br><span class="info-box-label">'.$arraydata['product']->getNomUrl(1).'</span>';
1968 if (property_exists($this, 'qty')) {
1969 $return .= ' <span class="info-box-label">('.$langs->trans("Qty").' '.$this->qty.')</span>';
1970 }
1971 } else {
1972 if (property_exists($this, 'qty')) {
1973 $return .= '<br><span class="info-box-label">'.$langs->trans('Quantity').' : '.$this->qty.'</span>';
1974 }
1975 }
1976 if (method_exists($this, 'getLibStatut')) {
1977 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
1978 }
1979 $return .= '</div>';
1980 $return .= '</div>';
1981 $return .= '</div>';
1982 return $return;
1983 }
1984}
1985
1986
1991{
1995 public $element = 'mrp_production';
1996
2000 public $table_element = 'mrp_production';
2001
2005 public $parent_element = 'mo';
2006
2010 public $fk_parent_attribute = 'fk_mo';
2011
2052 public $fields = array(
2053 'rowid' => array('type' => 'integer', 'label' => 'ID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
2054 'fk_mo' => array('type' => 'integer', 'label' => 'Mo', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 15),
2055 'origin_id' => array('type' => 'integer', 'label' => 'Origin', 'enabled' => 1, 'visible' => -1, 'notnull' => 0, 'position' => 17),
2056 'origin_type' => array('type' => 'varchar(10)', 'label' => 'Origin type', 'enabled' => 1, 'visible' => -1, 'notnull' => 0, 'position' => 18),
2057 'position' => array('type' => 'integer', 'label' => 'Position', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 20),
2058 'fk_product' => array('type' => 'integer', 'label' => 'Product', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 25),
2059 'fk_warehouse' => array('type' => 'integer', 'label' => 'Warehouse', 'enabled' => 1, 'visible' => -1, 'position' => 30),
2060 'qty' => array('type' => 'real', 'label' => 'Qty', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35),
2061 'qty_frozen' => array('type' => 'smallint', 'label' => 'QuantityFrozen', 'enabled' => 1, 'visible' => 1, 'default' => '0', 'notnull' => 1, 'position' => 105, 'css' => 'maxwidth50imp', 'help' => 'QuantityConsumedInvariable'),
2062 'disable_stock_change' => array('type' => 'smallint', 'label' => 'DisableStockChange', 'enabled' => 1, 'visible' => 1, 'default' => '0', 'notnull' => 1, 'position' => 108, 'css' => 'maxwidth50imp', 'help' => 'DisableStockChangeHelp'),
2063 'batch' => array('type' => 'varchar(30)', 'label' => 'Batch', 'enabled' => 1, 'visible' => -1, 'position' => 140),
2064 'role' => array('type' => 'varchar(10)', 'label' => 'Role', 'enabled' => 1, 'visible' => -1, 'position' => 145),
2065 'fk_mrp_production' => array('type' => 'integer', 'label' => 'Fk mrp production', 'enabled' => 1, 'visible' => -1, 'position' => 150),
2066 'fk_stock_movement' => array('type' => 'integer', 'label' => 'StockMovement', 'enabled' => 1, 'visible' => -1, 'position' => 155),
2067 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 160),
2068 'tms' => array('type' => 'timestamp', 'label' => 'Tms', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 165),
2069 'fk_user_creat' => array('type' => 'integer', 'label' => 'UserCreation', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 170),
2070 'fk_user_modif' => array('type' => 'integer', 'label' => 'UserModification', 'enabled' => 1, 'visible' => -1, 'position' => 175),
2071 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -1, 'position' => 180),
2072 'fk_default_workstation' => array('type' => 'integer', 'label' => 'DefaultWorkstation', 'enabled' => 1, 'visible' => 1, 'notnull' => 0, 'position' => 185),
2073 'fk_unit' => array('type' => 'int', 'label' => 'Unit', 'enabled' => 1, 'visible' => 1, 'notnull' => 0, 'position' => 186)
2074 );
2075
2076 public $rowid;
2077 public $fk_mo;
2078 public $origin_id;
2079 public $origin_type;
2080 public $position;
2081 public $fk_product;
2082 public $fk_warehouse;
2083
2087 public $qty;
2088
2092 public $qty_frozen;
2093 public $disable_stock_change;
2094 public $efficiency;
2095
2099 public $batch;
2100 public $role;
2101 public $fk_mrp_production;
2102 public $fk_stock_movement;
2103 public $import_key;
2104 public $fk_parent_line;
2105 public $fk_unit;
2106
2110 public $fk_default_workstation;
2111
2117 public function __construct(DoliDB $db)
2118 {
2119 global $langs;
2120
2121 $this->db = $db;
2122
2123 $this->ismultientitymanaged = 0;
2124 $this->isextrafieldmanaged = 1;
2125
2126 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
2127 $this->fields['rowid']['visible'] = 0;
2128 }
2129 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
2130 $this->fields['entity']['enabled'] = 0;
2131 }
2132
2133 // Unset fields that are disabled
2134 foreach ($this->fields as $key => $val) {
2135 if (isset($val['enabled']) && empty($val['enabled'])) {
2136 unset($this->fields[$key]);
2137 }
2138 }
2139
2140 // Translate some data of arrayofkeyval
2141 if (is_object($langs)) {
2142 foreach ($this->fields as $key => $val) {
2143 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
2144 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
2145 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
2146 }
2147 }
2148 }
2149 }
2150 }
2151
2159 public function create(User $user, $notrigger = 0)
2160 {
2161 if (empty($this->qty)) {
2162 $this->error = 'ErrorEmptyValueForQty';
2163 return -1;
2164 }
2165
2166 return $this->createCommon($user, $notrigger);
2167 }
2168
2176 public function fetch($id, $ref = null)
2177 {
2178 $result = $this->fetchCommon($id, $ref);
2179 return $result;
2180 }
2181
2193 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
2194 {
2195 dol_syslog(__METHOD__, LOG_DEBUG);
2196
2197 $records = array();
2198
2199 $sql = 'SELECT ';
2200 $sql .= $this->getFieldList();
2201 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
2202 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2203 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
2204 } else {
2205 $sql .= ' WHERE 1 = 1';
2206 }
2207
2208 // Deprecated.
2209 if (is_array($filter)) {
2210 $sqlwhere = array();
2211 if (count($filter) > 0) {
2212 foreach ($filter as $key => $value) {
2213 if ($key == 't.rowid') {
2214 $sqlwhere[] = $key." = ".((int) $value);
2215 } elseif (strpos($key, 'date') !== false) {
2216 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
2217 } else {
2218 $sqlwhere[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
2219 }
2220 }
2221 }
2222 if (count($sqlwhere) > 0) {
2223 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
2224 }
2225
2226 $filter = '';
2227 }
2228
2229 // Manage filter
2230 $errormessage = '';
2231 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
2232 if ($errormessage) {
2233 $this->errors[] = $errormessage;
2234 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2235 return -1;
2236 }
2237
2238 if (!empty($sortfield)) {
2239 $sql .= $this->db->order($sortfield, $sortorder);
2240 }
2241 if (!empty($limit)) {
2242 $sql .= $this->db->plimit($limit, $offset);
2243 }
2244
2245 $resql = $this->db->query($sql);
2246 if ($resql) {
2247 $num = $this->db->num_rows($resql);
2248 $i = 0;
2249 while ($i < ($limit ? min($limit, $num) : $num)) {
2250 $obj = $this->db->fetch_object($resql);
2251
2252 $record = new self($this->db);
2253 $record->setVarsFromFetchObj($obj);
2254
2255 $records[$record->id] = $record;
2256
2257 $i++;
2258 }
2259 $this->db->free($resql);
2260
2261 return $records;
2262 } else {
2263 $this->errors[] = 'Error '.$this->db->lasterror();
2264 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2265
2266 return -1;
2267 }
2268 }
2269
2277 public function update(User $user, $notrigger = 0)
2278 {
2279 return $this->updateCommon($user, $notrigger);
2280 }
2281
2289 public function delete(User $user, $notrigger = 0)
2290 {
2291 return $this->deleteCommon($user, $notrigger);
2292 //return $this->deleteCommon($user, $notrigger, 1);
2293 }
2294}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition security.php:626
$object ref
Definition info.php:79
Class for BOM.
Definition bom.class.php:45
Parent class of all other business classes (invoices, contracts, proposals, orders,...
deleteLineCommon(User $user, $idline, $notrigger=0)
Delete a line of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
createCommon(User $user, $notrigger=0)
Create object in the database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
updateCommon(User $user, $notrigger=0)
Update object into database.
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.
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.
deleteCommon(User $user, $notrigger=0, $forcechilddeletion=0)
Delete object in 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:36
__construct(DoliDB $db)
Constructor.
Definition mo.class.php:248
fetchLinesLinked($role, $lineid=0)
Get list of lines linked to current line for a defined role.
Definition mo.class.php:569
getMoChilds()
Function used to return children 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:465
getNextNumRef($prod)
Returns the reference to the following non used MO depending on the active numbering module defined i...
create(User $user, $notrigger=0)
Create object into database.
Definition mo.class.php:288
fetch($id, $ref=null)
Load object in memory from the database.
Definition mo.class.php:448
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the database.
Definition mo.class.php:485
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.
getMoParent()
Function used to return children of Mo.
getLinesArray($rolefilter='')
Create an array of lines.
updateProduction(User $user, $notrigger=0)
Update quantities in lines to consume and/or lines to produce.
Definition mo.class.php:807
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...
update(User $user, $notrigger=0)
Update object into database.
Definition mo.class.php:656
getAllMoChilds($depth=0)
Function used to return all child MOs recursively.
createProduction(User $user, $notrigger=0)
Erase and update the line to consume and to produce.
Definition mo.class.php:690
deleteLine(User $user, $idline, $notrigger=0, $fk_movement=0)
Delete a line of object in database.
Definition mo.class.php:898
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)
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
getTooltipContentArray($params)
getTooltipContentArray
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
getLibStatut($mode=0)
Return label of the status.
info($id)
Load the info information in the object.
countMovements()
Count number of movement with origin of MO.
Definition mo.class.php:621
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition mo.class.php:346
Class MoLine.
update(User $user, $notrigger=0)
Update object into database.
create(User $user, $notrigger=0)
Create object into database.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the database.
__construct(DoliDB $db)
Constructor.
$parent_element
fetch($id, $ref=null)
Load object in memory from the database.
$fields
'type' field format: 'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortf...
$fk_parent_attribute
Class to manage stock movements.
Class to manage products or services.
Class to manage Dolibarr users.
dol_dir_list($utf8_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:63
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.