dolibarr 20.0.0
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_creation;
147
151 public $date_valid;
152
153 public $fk_user_creat;
154 public $fk_user_modif;
155 public $import_key;
156 public $status;
157
161 public $fk_product;
162
166 public $product;
167
171 public $date_start_planned;
172
176 public $date_end_planned;
177
181 public $fk_bom;
182
186 public $bom;
187
191 public $fk_project;
192
197 public $oldQty;
198
199
200 // If this object has a subtable with lines
201
205 public $table_element_line = 'mrp_production';
206
210 public $fk_element = 'fk_mo';
211
215 public $class_element_line = 'MoLine';
216
220 protected $childtables = array();
221
225 protected $childtablesoncascade = array('mrp_production');
226
230 public $lines = array();
231
235 public $line = null;
236
240 public $fk_parent_line;
241
245 public $tpl = array();
246
247
253 public function __construct(DoliDB $db)
254 {
255 global $langs;
256
257 $this->db = $db;
258
259 $this->ismultientitymanaged = 1;
260 $this->isextrafieldmanaged = 1;
261
262 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
263 $this->fields['rowid']['visible'] = 0;
264 }
265 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
266 $this->fields['entity']['enabled'] = 0;
267 }
268
269 // Unset fields that are disabled
270 foreach ($this->fields as $key => $val) {
271 if (isset($val['enabled']) && empty($val['enabled'])) {
272 unset($this->fields[$key]);
273 }
274 }
275
276 // Translate some data of arrayofkeyval
277 foreach ($this->fields as $key => $val) {
278 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
279 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
280 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
281 }
282 }
283 }
284 }
285
293 public function create(User $user, $notrigger = 0)
294 {
295 $error = 0;
296 $idcreated = 0;
297
298 // 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
299 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && !getDolGlobalString('ALLOW_USE_KITS_INTO_BOM_AND_MO') && $this->fk_product > 0) {
300 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
301 $tmpproduct = new Product($this->db);
302 $tmpproduct->fetch($this->fk_product);
303 if ($tmpproduct->hasFatherOrChild(1) > 0) {
304 $this->error = 'ErrorAVirtualProductCantBeUsedIntoABomOrMo';
305 $this->errors[] = $this->error;
306 return -1;
307 }
308 }
309
310 $this->db->begin();
311
312 if ($this->fk_bom > 0) {
313 // If there is a known BOM, we force the type of MO to the type of BOM
314 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
315 $tmpbom = new BOM($this->db);
316 $tmpbom->fetch($this->fk_bom);
317
318 $this->mrptype = $tmpbom->bomtype;
319 }
320
321 if (!$error) {
322 $idcreated = $this->createCommon($user, $notrigger);
323 if ($idcreated <= 0) {
324 $error++;
325 }
326 }
327
328 if (!$error) {
329 $result = $this->createProduction($user, $notrigger); // Insert lines from BOM
330 if ($result <= 0) {
331 $error++;
332 }
333 }
334
335 if (!$error) {
336 $this->db->commit();
337 return $idcreated;
338 } else {
339 $this->db->rollback();
340 return -1;
341 }
342 }
343
351 public function createFromClone(User $user, $fromid)
352 {
353 global $langs, $extrafields;
354 $error = 0;
355
356 dol_syslog(__METHOD__, LOG_DEBUG);
357
358 $object = new self($this->db);
359
360 $this->db->begin();
361
362 // Load source object
363 $result = $object->fetchCommon($fromid);
364 if ($result > 0 && !empty($object->table_element_line)) {
365 $object->fetchLines();
366 }
367
368 // get lines so they will be clone
369 //foreach($this->lines as $line)
370 // $line->fetch_optionals();
371
372 // Reset some properties
373 unset($object->id);
374 unset($object->fk_user_creat);
375 unset($object->import_key);
376
377 // We make $object->lines empty to sort it without produced and consumed lines
378 $TLines = $object->lines;
379 $object->lines = array();
380
381 // Remove produced and consumed lines
382 foreach ($TLines as $key => $line) {
383 if (in_array($line->role, array('consumed', 'produced'))) {
384 unset($object->lines[$key]);
385 } else {
386 $object->lines[] = $line;
387 }
388 }
389
390
391 // Clear fields
392 $object->ref = empty($this->fields['ref']['default']) ? "copy_of_".$object->ref : $this->fields['ref']['default'];
393 $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
394 $object->status = self::STATUS_DRAFT;
395 // ...
396 // Clear extrafields that are unique
397 if (is_array($object->array_options) && count($object->array_options) > 0) {
398 $extrafields->fetch_name_optionals_label($this->table_element);
399 foreach ($object->array_options as $key => $option) {
400 $shortkey = preg_replace('/options_/', '', $key);
401 if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
402 //var_dump($key);
403 //var_dump($clonedObj->array_options[$key]); exit;
404 unset($object->array_options[$key]);
405 }
406 }
407 }
408
409 // Create clone
410 $object->context['createfromclone'] = 'createfromclone';
411 $result = $object->createCommon($user);
412 if ($result < 0) {
413 $error++;
414 $this->error = $object->error;
415 $this->errors = $object->errors;
416 }
417
418 if (!$error) {
419 // copy internal contacts
420 if ($this->copy_linked_contact($object, 'internal') < 0) {
421 $error++;
422 }
423 }
424
425 if (!$error) {
426 // copy external contacts if same company
427 if (property_exists($this, 'socid') && $this->socid == $object->socid) {
428 if ($this->copy_linked_contact($object, 'external') < 0) {
429 $error++;
430 }
431 }
432 }
433
434 unset($object->context['createfromclone']);
435
436 // End
437 if (!$error) {
438 $this->db->commit();
439 return $object;
440 } else {
441 $this->db->rollback();
442 return -1;
443 }
444 }
445
453 public function fetch($id, $ref = null)
454 {
455 $result = $this->fetchCommon($id, $ref);
456 if ($result > 0 && !empty($this->table_element_line)) {
457 $this->fetchLines();
458 }
459
460 $this->socid = $this->fk_soc;
461
462 return $result;
463 }
464
470 public function fetchLines()
471 {
472 $this->lines = array();
473
474 $result = $this->fetchLinesCommon();
475 return $result;
476 }
477
478
490 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
491 {
492 dol_syslog(__METHOD__, LOG_DEBUG);
493
494 $records = array();
495
496 $sql = 'SELECT ';
497 $sql .= $this->getFieldList();
498 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
499 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
500 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
501 } else {
502 $sql .= ' WHERE 1 = 1';
503 }
504
505 // Manage filter
506 if (is_array($filter)) {
507 $sqlwhere = array();
508 if (count($filter) > 0) {
509 foreach ($filter as $key => $value) {
510 if ($key == 't.rowid') {
511 $sqlwhere[] = $this->db->sanitize($key)." = ".((int) $value);
512 } elseif (strpos($key, 'date') !== false) {
513 $sqlwhere[] = $this->db->sanitize($key)." = '".$this->db->idate($value)."'";
514 } else {
515 $sqlwhere[] = $this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
516 }
517 }
518 }
519 if (count($sqlwhere) > 0) {
520 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
521 }
522
523 $filter = '';
524 }
525
526 // Manage filter
527 $errormessage = '';
528 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
529 if ($errormessage) {
530 $this->errors[] = $errormessage;
531 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
532 return -1;
533 }
534
535 if (!empty($sortfield)) {
536 $sql .= $this->db->order($sortfield, $sortorder);
537 }
538 if (!empty($limit)) {
539 $sql .= $this->db->plimit($limit, $offset);
540 }
541
542 $resql = $this->db->query($sql);
543 if ($resql) {
544 $num = $this->db->num_rows($resql);
545 $i = 0;
546 while ($i < min($limit, $num)) {
547 $obj = $this->db->fetch_object($resql);
548
549 $record = new self($this->db);
550 $record->setVarsFromFetchObj($obj);
551
552 $records[$record->id] = $record;
553
554 $i++;
555 }
556 $this->db->free($resql);
557
558 return $records;
559 } else {
560 $this->errors[] = 'Error '.$this->db->lasterror();
561 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
562
563 return -1;
564 }
565 }
566
574 public function fetchLinesLinked($role, $lineid = 0)
575 {
576 $resarray = array();
577 $mostatic = new MoLine($this->db);
578
579 $sql = 'SELECT ';
580 $sql .= $mostatic->getFieldList();
581 $sql .= ' FROM '.MAIN_DB_PREFIX.$mostatic->table_element.' as t';
582 $sql .= " WHERE t.role = '".$this->db->escape($role)."'";
583 if ($lineid > 0) {
584 $sql .= ' AND t.fk_mrp_production = '.((int) $lineid);
585 } else {
586 $sql .= 'AND t.fk_mo = '.((int) $this->id);
587 }
588
589 $resql = $this->db->query($sql);
590 if ($resql) {
591 $num = $this->db->num_rows($resql);
592
593 $i = 0;
594 while ($i < $num) {
595 $obj = $this->db->fetch_object($resql);
596 if ($obj) {
597 $resarray[] = array(
598 'rowid' => $obj->rowid,
599 'date' => $this->db->jdate($obj->date_creation),
600 'qty' => $obj->qty,
601 'role' => $obj->role,
602 'fk_product' => $obj->fk_product,
603 'fk_warehouse' => $obj->fk_warehouse,
604 'batch' => $obj->batch,
605 'fk_stock_movement' => $obj->fk_stock_movement,
606 'fk_unit' => $obj->fk_unit
607 );
608 }
609
610 $i++;
611 }
612
613 return $resarray;
614 } else {
615 $this->error = $this->db->lasterror();
616 return array();
617 }
618 }
619
620
626 public function countMovements()
627 {
628 $result = 0;
629
630 $sql = 'SELECT COUNT(rowid) as nb FROM '.MAIN_DB_PREFIX.'stock_mouvement as sm';
631 $sql .= " WHERE sm.origintype = 'mo' and sm.fk_origin = ".((int) $this->id);
632
633 $resql = $this->db->query($sql);
634 if ($resql) {
635 $num = $this->db->num_rows($resql);
636
637 $i = 0;
638 while ($i < $num) {
639 $obj = $this->db->fetch_object($resql);
640 if ($obj) {
641 $result = $obj->nb;
642 }
643
644 $i++;
645 }
646 } else {
647 $this->error = $this->db->lasterror();
648 }
649
650 return $result;
651 }
652
653
661 public function update(User $user, $notrigger = 0)
662 {
663 $error = 0;
664
665 $this->db->begin();
666
667 $result = $this->updateCommon($user, $notrigger);
668 if ($result <= 0) {
669 $error++;
670 }
671
672 // Update the lines (the qty) to consume or to produce
673 $result = $this->updateProduction($user, $notrigger);
674 if ($result <= 0) {
675 $error++;
676 }
677
678 if (!$error) {
679 $this->db->commit();
680 return 1;
681 } else {
682 $this->db->rollback();
683 return -1;
684 }
685 }
686
687
695 public function createProduction(User $user, $notrigger = 0)
696 {
697 $error = 0;
698 $role = "";
699
700 if ($this->status != self::STATUS_DRAFT) {
701 return -1;
702 }
703
704 $this->db->begin();
705
706 // Insert lines in mrp_production table from BOM data
707 if (!$error) {
708 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'mrp_production WHERE fk_mo = '.((int) $this->id);
709 $this->db->query($sql);
710
711 $moline = new MoLine($this->db);
712
713 // Line to produce
714 $moline->fk_mo = $this->id;
715 $moline->qty = $this->qty;
716 $moline->fk_product = $this->fk_product;
717 $moline->position = 1;
718 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
719 $tmpproduct = new Product($this->db);
720 $tmpproduct->fetch($this->fk_product);
721 $moline->fk_unit = $tmpproduct->fk_unit;
722
723 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to produce.
724 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
725 $bom = new BOM($this->db);
726 $bom->fetch($this->fk_bom);
727 if ($bom->bomtype == 1) {
728 $role = 'toproduce';
729 $moline->role = 'toconsume';
730 } else {
731 $role = 'toconsume';
732 $moline->role = 'toproduce';
733 }
734 } else {
735 if ($this->mrptype == 1) {
736 $moline->role = 'toconsume';
737 } else {
738 $moline->role = 'toproduce';
739 }
740 }
741
742 $resultline = $moline->create($user, false); // Never use triggers here
743 if ($resultline <= 0) {
744 $error++;
745 $this->error = $moline->error;
746 $this->errors = $moline->errors;
747 }
748
749 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to consume.
750 if ($bom->id > 0) {
751 // Lines to consume
752 if (!$error) {
753 foreach ($bom->lines as $line) {
754 $moline = new MoLine($this->db);
755
756 $moline->fk_mo = $this->id;
757 $moline->origin_id = $line->id;
758 $moline->origin_type = 'bomline';
759 if (!empty($line->fk_unit)) {
760 $moline->fk_unit = $line->fk_unit;
761 }
762 if ($line->qty_frozen) {
763 $moline->qty = $line->qty; // Qty to consume does not depends on quantity to produce
764 } else {
765 $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
766 }
767 if ($moline->qty <= 0) {
768 $error++;
769 $this->error = "BadValueForquantityToConsume";
770 break;
771 } else {
772 $moline->fk_product = $line->fk_product;
773 $moline->role = $role;
774 $moline->position = $line->position;
775 $moline->qty_frozen = $line->qty_frozen;
776 $moline->disable_stock_change = $line->disable_stock_change;
777 if (!empty($line->fk_default_workstation)) {
778 $moline->fk_default_workstation = $line->fk_default_workstation;
779 }
780
781 $resultline = $moline->create($user, false); // Never use triggers here
782 if ($resultline <= 0) {
783 $error++;
784 $this->error = $moline->error;
785 $this->errors = $moline->errors;
786 dol_print_error($this->db, $moline->error, $moline->errors);
787 break;
788 }
789 }
790 }
791 }
792 }
793 }
794 }
795
796 if (!$error) {
797 $this->db->commit();
798 return 1;
799 } else {
800 $this->db->rollback();
801 return -1;
802 }
803 }
804
812 public function updateProduction(User $user, $notrigger = 0)
813 {
814 $error = 0;
815
816 if ($this->status != self::STATUS_DRAFT) {
817 return 1;
818 }
819
820 $this->db->begin();
821
822 $oldQty = $this->oldQty;
823 $newQty = $this->qty;
824 if ($newQty != $oldQty && !empty($this->oldQty)) {
825 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "mrp_production WHERE fk_mo = " . (int) $this->id;
826 $resql = $this->db->query($sql);
827 if ($resql) {
828 while ($obj = $this->db->fetch_object($resql)) {
829 $moLine = new MoLine($this->db);
830 $res = $moLine->fetch($obj->rowid);
831 if (!$res) {
832 $error++;
833 }
834
835 if ($moLine->role == 'toconsume' || $moLine->role == 'toproduce') {
836 if (empty($moLine->qty_frozen)) {
837 $qty = $newQty * $moLine->qty / $oldQty;
838 $moLine->qty = (float) price2num($qty, 'MS');
839 $res = $moLine->update($user);
840 if (!$res) {
841 $error++;
842 }
843 }
844 }
845 }
846 }
847 }
848 if (!$error) {
849 $this->db->commit();
850 return 1;
851 } else {
852 $this->db->rollback();
853 return -1;
854 }
855 }
856
857
866 public function delete(User $user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
867 {
868 $error = 0;
869 $this->db->begin();
870
871 if ($also_cancel_consumed_and_produced_lines) {
872 $result = $this->cancelConsumedAndProducedLines($user, 0, false, $notrigger);
873 if ($result < 0) {
874 $error++;
875 }
876 }
877
878 if (!$error) {
879 $result = $this->deleteCommon($user, $notrigger);
880 if ($result < 0) {
881 $error++;
882 }
883 }
884
885 if ($error) {
886 $this->db->rollback();
887 return -1;
888 } else {
889 $this->db->commit();
890 return 1;
891 }
892 }
893
903 public function deleteLine(User $user, $idline, $notrigger = 0, $fk_movement = 0)
904 {
905 global $langs;
906 $langs->loadLangs(array('stocks', 'mrp'));
907
908 if ($this->status < 0) {
909 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
910 return -2;
911 }
912 $productstatic = new Product($this->db);
913
914 $arrayoflines = $this->fetchLinesLinked('consumed', $idline); // Get lines consumed under the one to delete
915
916 $result = 0;
917
918 $this->db->begin();
919
920 if (!empty($arrayoflines)) {
921 // If there is child lines
922 $stockmove = new MouvementStock($this->db);
923 $stockmove->setOrigin($this->element, $this->id);
924
925 if (!empty($fk_movement)) {
926 // The fk_movement was not recorded so we try to guess the product and quantity to restore.
927 $moline = new MoLine($this->db);
928 $TArrayMoLine = $moline->fetchAll('', '', 1, 0, '(fk_stock_movement:=:'.((int) $fk_movement).')');
929 $moline = array_shift($TArrayMoLine);
930
931 $movement = new MouvementStock($this->db);
932 $movement->fetch($fk_movement);
933 $productstatic->fetch($movement->product_id);
934 $qtytoprocess = $movement->qty;
935
936 // Reverse stock movement
937 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
938 $codemovementCancel = $langs->trans("StockIncrease");
939
940 if (($qtytoprocess >= 0)) {
941 $idstockmove = $stockmove->reception($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, '', '', $movement->batch, dol_now(), 0, $codemovementCancel);
942 } else {
943 $idstockmove = $stockmove->livraison($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $movement->batch, 0, $codemovementCancel);
944 }
945 if ($idstockmove < 0) {
946 $this->error++;
947 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
948 } else {
949 $result = $moline->delete($user, $notrigger);
950 }
951 } else {
952 // Loop on each child lines
953 foreach ($arrayoflines as $key => $arrayofline) {
954 $lineDetails = $arrayoflines[$key];
955 $productstatic->fetch($lineDetails['fk_product']);
956 $qtytoprocess = $lineDetails['qty'];
957
958 // Reverse stock movement
959 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
960 $codemovementCancel = $langs->trans("StockIncrease");
961
962
963 if ($qtytoprocess >= 0) {
964 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
965 } else {
966 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
967 }
968 if ($idstockmove < 0) {
969 $this->error++;
970 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
971 } else {
972 $moline = new MoLine($this->db);
973 $moline->fetch($lineDetails['rowid']);
974
975 $resdel = $moline->delete($user, $notrigger);
976 if ($resdel < 0) {
977 $this->error++;
978 setEventMessages($moline->error, $moline->errors, 'errors');
979 }
980 }
981 }
982
983 if (empty($this->error)) {
984 $result = $this->deleteLineCommon($user, $idline, $notrigger);
985 }
986 }
987 } else {
988 // No child lines
989 $result = $this->deleteLineCommon($user, $idline, $notrigger);
990 }
991
992 if (!empty($this->error) || $result <= 0) {
993 $this->db->rollback();
994 } else {
995 $this->db->commit();
996 }
997
998 return $result;
999 }
1000
1001
1009 public function getNextNumRef($prod)
1010 {
1011 global $langs, $conf;
1012 $langs->load("mrp");
1013
1014 if (getDolGlobalString('MRP_MO_ADDON')) {
1015 $mybool = false;
1016
1017 $file = getDolGlobalString('MRP_MO_ADDON') . ".php";
1018 $classname = getDolGlobalString('MRP_MO_ADDON');
1019
1020 // Include file with class
1021 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1022 foreach ($dirmodels as $reldir) {
1023 $dir = dol_buildpath($reldir."core/modules/mrp/");
1024
1025 // Load file with numbering class (if found)
1026 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1027 }
1028
1029 if ($mybool === false) {
1030 dol_print_error(null, "Failed to include file ".$file);
1031 return '';
1032 }
1033
1034 $obj = new $classname();
1035 $numref = $obj->getNextValue($prod, $this);
1036
1037 if ($numref != "") {
1038 return $numref;
1039 } else {
1040 $this->error = $obj->error;
1041 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1042 return "";
1043 }
1044 } else {
1045 print $langs->trans("Error")." ".$langs->trans("Error_MRP_MO_ADDON_NotDefined");
1046 return "";
1047 }
1048 }
1049
1057 public function validate($user, $notrigger = 0)
1058 {
1059 global $conf;
1060
1061 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1062
1063 $error = 0;
1064
1065 // Protection
1066 if ($this->status == self::STATUS_VALIDATED) {
1067 dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING);
1068 return 0;
1069 }
1070
1071 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->create))
1072 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->mrp_advance->validate))))
1073 {
1074 $this->error='NotEnoughPermissions';
1075 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
1076 return -1;
1077 }*/
1078
1079 $now = dol_now();
1080
1081 $this->db->begin();
1082
1083 // Define new ref
1084 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1085 $this->fetch_product();
1086 $num = $this->getNextNumRef($this->product);
1087 } else {
1088 $num = $this->ref;
1089 }
1090 $this->newref = $num;
1091
1092 // Validate
1093 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1094 $sql .= " SET ref = '".$this->db->escape($num)."',";
1095 $sql .= " status = ".self::STATUS_VALIDATED.",";
1096 $sql .= " date_valid='".$this->db->idate($now)."',";
1097 $sql .= " fk_user_valid = ".$user->id;
1098 $sql .= " WHERE rowid = ".((int) $this->id);
1099
1100 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
1101 $resql = $this->db->query($sql);
1102 if (!$resql) {
1103 dol_print_error($this->db);
1104 $this->error = $this->db->lasterror();
1105 $error++;
1106 }
1107
1108 if (!$error && !$notrigger) {
1109 // Call trigger
1110 $result = $this->call_trigger('MRP_MO_VALIDATE', $user);
1111 if ($result < 0) {
1112 $error++;
1113 }
1114 // End call triggers
1115 }
1116
1117 if (!$error) {
1118 $this->oldref = $this->ref;
1119
1120 // Rename directory if dir was a temporary ref
1121 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1122 // Now we rename also files into index
1123 $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)."'";
1124 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'mrp/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1125 $resql = $this->db->query($sql);
1126 if (!$resql) {
1127 $error++;
1128 $this->error = $this->db->lasterror();
1129 }
1130 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'mrp/".$this->db->escape($this->newref)."'";
1131 $sql .= " WHERE filepath = 'mrp/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1132 $resql = $this->db->query($sql);
1133 if (!$resql) {
1134 $error++;
1135 $this->error = $this->db->lasterror();
1136 }
1137
1138 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1139 $oldref = dol_sanitizeFileName($this->ref);
1140 $newref = dol_sanitizeFileName($num);
1141 $dirsource = $conf->mrp->dir_output.'/'.$oldref;
1142 $dirdest = $conf->mrp->dir_output.'/'.$newref;
1143 if (!$error && file_exists($dirsource)) {
1144 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
1145
1146 if (@rename($dirsource, $dirdest)) {
1147 dol_syslog("Rename ok");
1148 // Rename docs starting with $oldref with $newref
1149 $listoffiles = dol_dir_list($conf->mrp->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1150 foreach ($listoffiles as $fileentry) {
1151 $dirsource = $fileentry['name'];
1152 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1153 $dirsource = $fileentry['path'].'/'.$dirsource;
1154 $dirdest = $fileentry['path'].'/'.$dirdest;
1155 @rename($dirsource, $dirdest);
1156 }
1157 }
1158 }
1159 }
1160 }
1161
1162 // Set new ref and current status
1163 if (!$error) {
1164 $this->ref = $num;
1165 $this->status = self::STATUS_VALIDATED;
1166 }
1167
1168 if (!$error) {
1169 $this->db->commit();
1170 return 1;
1171 } else {
1172 $this->db->rollback();
1173 return -1;
1174 }
1175 }
1176
1184 public function setDraft($user, $notrigger = 0)
1185 {
1186 // Protection
1187 if ($this->status <= self::STATUS_DRAFT) {
1188 return 0;
1189 }
1190
1191 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1192 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1193 {
1194 $this->error='Permission denied';
1195 return -1;
1196 }*/
1197
1198 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'MRP_MO_UNVALIDATE');
1199 }
1200
1209 public function cancel($user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
1210 {
1211 // Protection
1212 if ($this->status != self::STATUS_VALIDATED && $this->status != self::STATUS_INPROGRESS) {
1213 return 0;
1214 }
1215
1216 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1217 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1218 {
1219 $this->error='Permission denied';
1220 return -1;
1221 }*/
1222
1223 $error = 0;
1224 $this->db->begin();
1225
1226 if ($also_cancel_consumed_and_produced_lines) {
1227 $result = $this->cancelConsumedAndProducedLines($user, 0, true, $notrigger);
1228 if ($result < 0) {
1229 $error++;
1230 }
1231 }
1232
1233 if (!$error) {
1234 $result = $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'MRP_MO_CANCEL');
1235 if ($result < 0) {
1236 $error++;
1237 }
1238 }
1239
1240 if ($error) {
1241 $this->db->rollback();
1242 return -1;
1243 } else {
1244 $this->db->commit();
1245 return 1;
1246 }
1247 }
1248
1256 public function reopen($user, $notrigger = 0)
1257 {
1258 // Protection
1259 if ($this->status != self::STATUS_PRODUCED && $this->status != self::STATUS_CANCELED) {
1260 return 0;
1261 }
1262
1263 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1264 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1265 {
1266 $this->error='Permission denied';
1267 return -1;
1268 }*/
1269
1270 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'MRP_MO_REOPEN');
1271 }
1272
1282 public function cancelConsumedAndProducedLines($user, $mode = 0, $also_delete_lines = false, $notrigger = 0)
1283 {
1284 global $langs;
1285
1286 if (!isModEnabled('stock')) {
1287 return 1;
1288 }
1289
1290 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1291 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php';
1292 $error = 0;
1293 $langs->load('stocks');
1294
1295 $this->db->begin();
1296
1297 // Cancel consumed lines
1298 if (empty($mode) || $mode == 1) {
1299 $arrayoflines = $this->fetchLinesLinked('consumed');
1300 if (!empty($arrayoflines)) {
1301 foreach ($arrayoflines as $key => $lineDetails) {
1302 $productstatic = new Product($this->db);
1303 $productstatic->fetch($lineDetails['fk_product']);
1304 $qtytoprocess = $lineDetails['qty'];
1305
1306 // Reverse stock movement
1307 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1308 $codemovementCancel = $langs->trans("StockIncrease");
1309
1310 $stockmove = new MouvementStock($this->db);
1311 $stockmove->setOrigin($this->element, $this->id);
1312 if ($qtytoprocess >= 0) {
1313 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1314 } else {
1315 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1316 }
1317 if ($idstockmove < 0) {
1318 $this->error = $stockmove->error;
1319 $this->errors = $stockmove->errors;
1320 $error++;
1321 break;
1322 }
1323
1324 if ($also_delete_lines) {
1325 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1326 if ($result < 0) {
1327 $error++;
1328 break;
1329 }
1330 }
1331 }
1332 }
1333 }
1334
1335 // Cancel produced lines
1336 if (empty($mode) || $mode == 2) {
1337 $arrayoflines = $this->fetchLinesLinked('produced');
1338 if (!empty($arrayoflines)) {
1339 foreach ($arrayoflines as $key => $lineDetails) {
1340 $productstatic = new Product($this->db);
1341 $productstatic->fetch($lineDetails['fk_product']);
1342 $qtytoprocess = $lineDetails['qty'];
1343
1344 // Reverse stock movement
1345 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1346 $codemovementCancel = $langs->trans("StockDecrease");
1347
1348 $stockmove = new MouvementStock($this->db);
1349 $stockmove->setOrigin($this->element, $this->id);
1350 if ($qtytoprocess >= 0) {
1351 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1352 } else {
1353 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1354 }
1355 if ($idstockmove < 0) {
1356 $this->error = $stockmove->error;
1357 $this->errors = $stockmove->errors;
1358 $error++;
1359 break;
1360 }
1361
1362 if ($also_delete_lines) {
1363 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1364 if ($result < 0) {
1365 $error++;
1366 break;
1367 }
1368 }
1369 }
1370 }
1371 }
1372
1373 if ($error) {
1374 $this->db->rollback();
1375 return -1;
1376 } else {
1377 $this->db->commit();
1378 return 1;
1379 }
1380 }
1381
1389 public function getTooltipContentArray($params)
1390 {
1391 global $langs;
1392
1393 $langs->loadLangs(['mrp', 'products']);
1394 $nofetch = isset($params['nofetch']) ? true : false;
1395
1396 $datas = [];
1397
1398 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ManufacturingOrder").'</u>';
1399 if (isset($this->status)) {
1400 $datas['picto'] .= ' '.$this->getLibStatut(5);
1401 }
1402 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1403 if (isset($this->label)) {
1404 $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1405 }
1406 if (isset($this->mrptype)) {
1407 $datas['type'] = '<br><b>'.$langs->trans('Type').':</b> '.$this->fields['mrptype']['arrayofkeyval'][$this->mrptype];
1408 }
1409 if (isset($this->qty)) {
1410 $datas['qty'] = '<br><b>'.$langs->trans('QtyToProduce').':</b> '.$this->qty;
1411 }
1412 if (!$nofetch && isset($this->fk_product)) {
1413 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1414 $product = new Product($this->db);
1415 $product->fetch($this->fk_product);
1416 $datas['product'] = '<br><b>'.$langs->trans('Product').':</b> '.$product->getNomUrl(1, '', 0, -1, 1);
1417 }
1418 if (!$nofetch && isset($this->fk_warehouse)) {
1419 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
1420 $warehouse = new Entrepot($this->db);
1421 $warehouse->fetch($this->fk_warehouse);
1422 $datas['warehouse'] = '<br><b>'.$langs->trans('WarehouseForProduction').':</b> '.$warehouse->getNomUrl(1, '', 0, 1);
1423 }
1424
1425 return $datas;
1426 }
1427
1438 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1439 {
1440 global $conf, $langs, $action, $hookmanager;
1441
1442 if (!empty($conf->dol_no_mouse_hover)) {
1443 $notooltip = 1; // Force disable tooltips
1444 }
1445
1446 $result = '';
1447 $params = [
1448 'id' => $this->id,
1449 'objecttype' => $this->element,
1450 'option' => $option,
1451 'nofetch' => 1,
1452 ];
1453 $classfortooltip = 'classfortooltip';
1454 $dataparams = '';
1455 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1456 $classfortooltip = 'classforajaxtooltip';
1457 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1458 $label = '';
1459 } else {
1460 $label = implode($this->getTooltipContentArray($params));
1461 }
1462
1463 $url = DOL_URL_ROOT.'/mrp/mo_card.php?id='.$this->id;
1464 if ($option == 'production') {
1465 $url = DOL_URL_ROOT.'/mrp/mo_production.php?id='.$this->id;
1466 }
1467
1468 if ($option != 'nolink') {
1469 // Add param to save lastsearch_values or not
1470 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1471 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1472 $add_save_lastsearch_values = 1;
1473 }
1474 if ($add_save_lastsearch_values) {
1475 $url .= '&save_lastsearch_values=1';
1476 }
1477 }
1478
1479 $linkclose = '';
1480 if (empty($notooltip)) {
1481 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1482 $label = $langs->trans("ShowMo");
1483 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1484 }
1485 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1486 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1487 } else {
1488 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1489 }
1490
1491 $linkstart = '<a href="'.$url.'"';
1492 $linkstart .= $linkclose.'>';
1493 $linkend = '</a>';
1494
1495 $result .= $linkstart;
1496 if ($withpicto) {
1497 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
1498 }
1499 if ($withpicto != 2) {
1500 $result .= $this->ref;
1501 }
1502 $result .= $linkend;
1503 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1504
1505 $hookmanager->initHooks(array('modao'));
1506 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1507 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1508 if ($reshook > 0) {
1509 $result = $hookmanager->resPrint;
1510 } else {
1511 $result .= $hookmanager->resPrint;
1512 }
1513
1514 return $result;
1515 }
1516
1523 public function getLibStatut($mode = 0)
1524 {
1525 return $this->LibStatut($this->status, $mode);
1526 }
1527
1528 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1536 public function LibStatut($status, $mode = 0)
1537 {
1538 // phpcs:enable
1539 if (empty($this->labelStatus)) {
1540 global $langs;
1541 //$langs->load("mrp");
1542 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1543 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('ValidatedToProduce');
1544 $this->labelStatus[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1545 $this->labelStatus[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1546 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1547
1548 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1549 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
1550 $this->labelStatusShort[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1551 $this->labelStatusShort[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1552 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1553 }
1554
1555 $statusType = 'status'.$status;
1556 if ($status == self::STATUS_VALIDATED) {
1557 $statusType = 'status1';
1558 }
1559 if ($status == self::STATUS_INPROGRESS) {
1560 $statusType = 'status4';
1561 }
1562 if ($status == self::STATUS_PRODUCED) {
1563 $statusType = 'status6';
1564 }
1565 if ($status == self::STATUS_CANCELED) {
1566 $statusType = 'status9';
1567 }
1568
1569 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1570 }
1571
1578 public function info($id)
1579 {
1580 $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1581 $sql .= ' fk_user_creat, fk_user_modif';
1582 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1583 $sql .= ' WHERE t.rowid = '.((int) $id);
1584 $result = $this->db->query($sql);
1585 if ($result) {
1586 if ($this->db->num_rows($result)) {
1587 $obj = $this->db->fetch_object($result);
1588
1589 $this->id = $obj->rowid;
1590
1591 $this->user_creation_id = $obj->fk_user_creat;
1592 $this->user_modification_id = $obj->fk_user_modif;
1593 $this->date_creation = $this->db->jdate($obj->datec);
1594 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1595 }
1596
1597 $this->db->free($result);
1598 } else {
1599 dol_print_error($this->db);
1600 }
1601 }
1602
1609 public function initAsSpecimen()
1610 {
1611 $ret = $this->initAsSpecimenCommon();
1612
1613 $this->lines = array();
1614
1615 return $ret;
1616 }
1617
1624 public function getLinesArray($rolefilter = '')
1625 {
1626 $this->lines = array();
1627
1628 $objectline = new MoLine($this->db);
1629
1630 $filter = '(fk_mo:=:'.((int) $this->id).')';
1631 if (!empty($rolefilter)) {
1632 $filter .= " AND (role:=:'".$this->db->escape($rolefilter)."')";
1633 }
1634 $result = $objectline->fetchAll('ASC', 'position', 0, 0, $filter);
1635
1636 if (is_numeric($result)) {
1637 $this->error = $objectline->error;
1638 $this->errors = $objectline->errors;
1639 return $result;
1640 } else {
1641 $this->lines = $result;
1642 return $this->lines;
1643 }
1644 }
1645
1657 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1658 {
1659 global $langs;
1660
1661 $langs->load("mrp");
1662
1663 if (!dol_strlen($modele)) {
1664 //$modele = 'standard';
1665 $modele = ''; // Remove this once a pdf_standard.php exists.
1666
1667 if ($this->model_pdf) {
1668 $modele = $this->model_pdf;
1669 } elseif (getDolGlobalString('MRP_MO_ADDON_PDF')) {
1670 $modele = getDolGlobalString('MRP_MO_ADDON_PDF');
1671 }
1672 }
1673
1674 $modelpath = "core/modules/mrp/doc/";
1675
1676 if (empty($modele)) {
1677 return 1; // Remove this once a pdf_standard.php exists.
1678 }
1679
1680 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1681 }
1682
1693 public function printOriginLinesList($restrictlist = '', $selectedLines = array())
1694 {
1695 global $langs, $hookmanager, $form, $action;
1696
1697 $langs->load('stocks');
1698 $text_stock_options = $langs->trans("RealStockDesc").'<br>';
1699 $text_stock_options .= $langs->trans("RealStockWillAutomaticallyWhen").'<br>';
1700 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT') || getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE') ? '- '.$langs->trans("DeStockOnShipment").'<br>' : '');
1701 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_VALIDATE_ORDER') ? '- '.$langs->trans("DeStockOnValidateOrder").'<br>' : '');
1702 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_BILL') ? '- '.$langs->trans("DeStockOnBill").'<br>' : '');
1703 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL') ? '- '.$langs->trans("ReStockOnBill").'<br>' : '');
1704 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER') ? '- '.$langs->trans("ReStockOnValidateOrder").'<br>' : '');
1705 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') ? '- '.$langs->trans("ReStockOnDispatchOrder").'<br>' : '');
1706 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION') || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE') ? '- '.$langs->trans("StockOnReception").'<br>' : '');
1707
1708 print '<tr class="liste_titre">';
1709 // Product or sub-bom
1710 print '<td class="linecoldescription">'.$langs->trans('Ref');
1711 if (getDolGlobalString('BOM_SUB_BOM')) {
1712 print ' &nbsp; <a id="show_all" href="#">'.img_picto('', 'folder-open', 'class="paddingright"').$langs->trans("ExpandAll").'</a>&nbsp;&nbsp;';
1713 print '<a id="hide_all" href="#">'.img_picto('', 'folder', 'class="paddingright"').$langs->trans("UndoExpandAll").'</a>&nbsp;';
1714 }
1715 print '</td>';
1716 // Qty
1717 print '<td class="right">'.$langs->trans('Qty');
1718 if ($this->bom->bomtype == 0) {
1719 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityOf", $this->bom->qty).')</span>';
1720 } else {
1721 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityToConsumeOf", $this->bom->qty).')</span>';
1722 }
1723 // Unit
1724 print '<td class="right">'.$langs->trans('Unit');
1725
1726 print '</td>';
1727 print '<td class="center">'.$form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1).'</td>';
1728 print '<td class="center">'.$form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc")).'</td>';
1729 print '<td class="center">'.$langs->trans('QtyFrozen').'</td>';
1730 print '<td class="center">'.$langs->trans('DisableStockChange').'</td>';
1731 print '<td class="center">'.$langs->trans('MoChildGenerate').'</td>';
1732 //print '<td class="center">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
1733 //print '<td class="center"></td>';
1734 print '</tr>';
1735 $i = 0;
1736
1737 if (!empty($this->lines)) {
1738 foreach ($this->lines as $line) {
1739 $reshook = 0;
1740 if (is_object($hookmanager)) {
1741 $parameters = array('line' => $line, 'i' => $i, 'restrictlist' => $restrictlist, 'selectedLines' => $selectedLines);
1742 if (!empty($line->fk_parent_line)) {
1743 $parameters['fk_parent_line'] = $line->fk_parent_line;
1744 }
1745 $reshook = $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1746 }
1747 if (empty($reshook)) {
1748 $this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
1749 }
1750
1751 $i++;
1752 }
1753 }
1754 }
1755
1756
1770 public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
1771 {
1772 $productstatic = new Product($this->db);
1773
1774 $this->tpl['id'] = $line->id;
1775
1776 $this->tpl['label'] = '';
1777 if (!empty($line->fk_product) && $line->fk_product > 0) {
1778 $productstatic->fetch($line->fk_product);
1779 $productstatic->load_virtual_stock();
1780 $this->tpl['label'] .= $productstatic->getNomUrl(1);
1781 //$this->tpl['label'].= ' - '.$productstatic->label;
1782 } else {
1783 // If origin MO line is not a product, but another MO
1784 // TODO
1785 }
1786
1787 $this->tpl['qty_bom'] = 1;
1788 if (is_object($this->bom) && $this->bom->qty > 1) {
1789 $this->tpl['qty_bom'] = $this->bom->qty;
1790 }
1791
1792 $this->tpl['stock'] = $productstatic->stock_reel;
1793 $this->tpl['seuil_stock_alerte'] = $productstatic->seuil_stock_alerte;
1794 $this->tpl['virtual_stock'] = $productstatic->stock_theorique;
1795 $this->tpl['qty'] = $line->qty;
1796 $this->tpl['fk_unit'] = $line->fk_unit;
1797 $this->tpl['qty_frozen'] = $line->qty_frozen;
1798 $this->tpl['disable_stock_change'] = $line->disable_stock_change;
1799 $this->tpl['efficiency'] = $line->efficiency;
1800
1801 global $conf; // used into template
1802 $res = include DOL_DOCUMENT_ROOT.'/mrp/tpl/originproductline.tpl.php';
1803 }
1804
1813 public static function replaceThirdparty($db, $origin_id, $dest_id)
1814 {
1815 $tables = array('mrp_mo');
1816
1817 return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1818 }
1819
1820
1826 public function getMoChilds()
1827 {
1828 $TMoChilds = array();
1829 $error = 0;
1830
1831 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_mo as mo_child";
1832 $sql .= " WHERE fk_parent_line IN ";
1833 $sql .= " (SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_production as line_parent";
1834 $sql .= " WHERE fk_mo=".((int) $this->id).")";
1835
1836 $resql = $this->db->query($sql);
1837
1838 if ($resql) {
1839 if ($this->db->num_rows($resql) > 0) {
1840 while ($obj = $this->db->fetch_object($resql)) {
1841 $MoChild = new Mo($this->db);
1842 $res = $MoChild->fetch($obj->rowid);
1843 if ($res > 0) {
1844 $TMoChilds[$MoChild->id] = $MoChild;
1845 } else {
1846 $error++;
1847 }
1848 }
1849 }
1850 } else {
1851 $error++;
1852 }
1853
1854 if ($error) {
1855 return -1;
1856 } else {
1857 return $TMoChilds;
1858 }
1859 }
1860
1867 public function getAllMoChilds($depth = 0)
1868 {
1869 if ($depth > 1000) {
1870 return -1;
1871 }
1872
1873 $TMoChilds = array();
1874 $error = 0;
1875
1876 $childMoList = $this->getMoChilds();
1877
1878 if ($childMoList == -1) {
1879 return -1;
1880 }
1881
1882 foreach ($childMoList as $childMo) {
1883 $TMoChilds[$childMo->id] = $childMo;
1884 }
1885
1886 foreach ($childMoList as $childMo) {
1887 $childMoChildren = $childMo->getAllMoChilds($depth + 1);
1888
1889 if ($childMoChildren == -1) {
1890 $error++;
1891 } else {
1892 foreach ($childMoChildren as $child) {
1893 $TMoChilds[$child->id] = $child;
1894 }
1895 }
1896 }
1897
1898 if ($error) {
1899 return -1;
1900 } else {
1901 return $TMoChilds;
1902 }
1903 }
1904
1905
1906
1912 public function getMoParent()
1913 {
1914 $MoParent = new Mo($this->db);
1915 $error = 0;
1916
1917 $sql = "SELECT lineparent.fk_mo as id_moparent FROM ".MAIN_DB_PREFIX."mrp_mo as mo";
1918 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."mrp_production lineparent ON mo.fk_parent_line = lineparent.rowid";
1919 $sql .= " WHERE mo.rowid = ".((int) $this->id);
1920
1921 $resql = $this->db->query($sql);
1922
1923 if ($resql) {
1924 if ($this->db->num_rows($resql) > 0) {
1925 $obj = $this->db->fetch_object($resql);
1926 $res = $MoParent->fetch($obj->id_moparent);
1927 if ($res < 0) {
1928 $error++;
1929 }
1930 } else {
1931 return 0;
1932 }
1933 } else {
1934 $error++;
1935 }
1936
1937 if ($error) {
1938 return -1;
1939 } else {
1940 return $MoParent;
1941 }
1942 }
1943
1951 public function getKanbanView($option = '', $arraydata = null)
1952 {
1953 global $langs;
1954
1955 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1956
1957 $return = '<div class="box-flex-item box-flex-grow-zero">';
1958 $return .= '<div class="info-box info-box-sm">';
1959 $return .= '<span class="info-box-icon bg-infobox-action">';
1960 $return .= img_picto('', $this->picto);
1961 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
1962 $return .= '</span>';
1963 $return .= '<div class="info-box-content">';
1964 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
1965 if ($selected >= 0) {
1966 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1967 }
1968 if (!empty($arraydata['bom'])) {
1969 $return .= '<br><span class="info-box-label">'.$arraydata['bom']->getNomUrl(1).'</span>';
1970 }
1971 if (!empty($arraydata['product'])) {
1972 $return .= '<br><span class="info-box-label">'.$arraydata['product']->getNomUrl(1).'</span>';
1973 if (property_exists($this, 'qty')) {
1974 $return .= ' <span class="info-box-label">('.$langs->trans("Qty").' '.$this->qty.')</span>';
1975 }
1976 } else {
1977 if (property_exists($this, 'qty')) {
1978 $return .= '<br><span class="info-box-label">'.$langs->trans('Quantity').' : '.$this->qty.'</span>';
1979 }
1980 }
1981 if (method_exists($this, 'getLibStatut')) {
1982 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
1983 }
1984 $return .= '</div>';
1985 $return .= '</div>';
1986 $return .= '</div>';
1987 return $return;
1988 }
1989}
1990
1991
1996{
2000 public $element = 'mrp_production';
2001
2005 public $table_element = 'mrp_production';
2006
2010 public $parent_element = 'mo';
2011
2015 public $fk_parent_attribute = 'fk_mo';
2016
2057 public $fields = array(
2058 'rowid' => array('type' => 'integer', 'label' => 'ID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
2059 'fk_mo' => array('type' => 'integer', 'label' => 'Mo', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 15),
2060 'origin_id' => array('type' => 'integer', 'label' => 'Origin', 'enabled' => 1, 'visible' => -1, 'notnull' => 0, 'position' => 17),
2061 'origin_type' => array('type' => 'varchar(10)', 'label' => 'Origin type', 'enabled' => 1, 'visible' => -1, 'notnull' => 0, 'position' => 18),
2062 'position' => array('type' => 'integer', 'label' => 'Position', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 20),
2063 'fk_product' => array('type' => 'integer', 'label' => 'Product', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 25),
2064 'fk_warehouse' => array('type' => 'integer', 'label' => 'Warehouse', 'enabled' => 1, 'visible' => -1, 'position' => 30),
2065 'qty' => array('type' => 'real', 'label' => 'Qty', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35),
2066 'qty_frozen' => array('type' => 'smallint', 'label' => 'QuantityFrozen', 'enabled' => 1, 'visible' => 1, 'default' => '0', 'notnull' => 1, 'position' => 105, 'css' => 'maxwidth50imp', 'help' => 'QuantityConsumedInvariable'),
2067 'disable_stock_change' => array('type' => 'smallint', 'label' => 'DisableStockChange', 'enabled' => 1, 'visible' => 1, 'default' => '0', 'notnull' => 1, 'position' => 108, 'css' => 'maxwidth50imp', 'help' => 'DisableStockChangeHelp'),
2068 'batch' => array('type' => 'varchar(30)', 'label' => 'Batch', 'enabled' => 1, 'visible' => -1, 'position' => 140),
2069 'role' => array('type' => 'varchar(10)', 'label' => 'Role', 'enabled' => 1, 'visible' => -1, 'position' => 145),
2070 'fk_mrp_production' => array('type' => 'integer', 'label' => 'Fk mrp production', 'enabled' => 1, 'visible' => -1, 'position' => 150),
2071 'fk_stock_movement' => array('type' => 'integer', 'label' => 'StockMovement', 'enabled' => 1, 'visible' => -1, 'position' => 155),
2072 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 160),
2073 'tms' => array('type' => 'timestamp', 'label' => 'Tms', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 165),
2074 'fk_user_creat' => array('type' => 'integer', 'label' => 'UserCreation', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 170),
2075 'fk_user_modif' => array('type' => 'integer', 'label' => 'UserModification', 'enabled' => 1, 'visible' => -1, 'position' => 175),
2076 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -1, 'position' => 180),
2077 'fk_default_workstation' => array('type' => 'integer', 'label' => 'DefaultWorkstation', 'enabled' => 1, 'visible' => 1, 'notnull' => 0, 'position' => 185),
2078 'fk_unit' => array('type' => 'int', 'label' => 'Unit', 'enabled' => 1, 'visible' => 1, 'notnull' => 0, 'position' => 186)
2079 );
2080
2081 public $rowid;
2082 public $fk_mo;
2083 public $origin_id;
2084 public $origin_type;
2085 public $position;
2086 public $fk_product;
2087 public $fk_warehouse;
2088
2092 public $qty;
2093
2097 public $qty_frozen;
2098 public $disable_stock_change;
2099 public $efficiency;
2100 public $batch;
2101 public $role;
2102 public $fk_mrp_production;
2103 public $fk_stock_movement;
2104 public $date_creation;
2105 public $fk_user_creat;
2106 public $fk_user_modif;
2107 public $import_key;
2108 public $fk_parent_line;
2109 public $fk_unit;
2110
2114 public $fk_default_workstation;
2115
2121 public function __construct(DoliDB $db)
2122 {
2123 global $langs;
2124
2125 $this->db = $db;
2126
2127 $this->ismultientitymanaged = 0;
2128 $this->isextrafieldmanaged = 1;
2129
2130 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
2131 $this->fields['rowid']['visible'] = 0;
2132 }
2133 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
2134 $this->fields['entity']['enabled'] = 0;
2135 }
2136
2137 // Unset fields that are disabled
2138 foreach ($this->fields as $key => $val) {
2139 if (isset($val['enabled']) && empty($val['enabled'])) {
2140 unset($this->fields[$key]);
2141 }
2142 }
2143
2144 // Translate some data of arrayofkeyval
2145 if (is_object($langs)) {
2146 foreach ($this->fields as $key => $val) {
2147 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
2148 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
2149 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
2150 }
2151 }
2152 }
2153 }
2154 }
2155
2163 public function create(User $user, $notrigger = 0)
2164 {
2165 if (empty($this->qty)) {
2166 $this->error = 'ErrorEmptyValueForQty';
2167 return -1;
2168 }
2169
2170 return $this->createCommon($user, $notrigger);
2171 }
2172
2180 public function fetch($id, $ref = null)
2181 {
2182 $result = $this->fetchCommon($id, $ref);
2183 return $result;
2184 }
2185
2197 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
2198 {
2199 dol_syslog(__METHOD__, LOG_DEBUG);
2200
2201 $records = array();
2202
2203 $sql = 'SELECT ';
2204 $sql .= $this->getFieldList();
2205 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
2206 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2207 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
2208 } else {
2209 $sql .= ' WHERE 1 = 1';
2210 }
2211
2212 // Deprecated.
2213 if (is_array($filter)) {
2214 $sqlwhere = array();
2215 if (count($filter) > 0) {
2216 foreach ($filter as $key => $value) {
2217 if ($key == 't.rowid') {
2218 $sqlwhere[] = $key." = ".((int) $value);
2219 } elseif (strpos($key, 'date') !== false) {
2220 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
2221 } else {
2222 $sqlwhere[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
2223 }
2224 }
2225 }
2226 if (count($sqlwhere) > 0) {
2227 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
2228 }
2229
2230 $filter = '';
2231 }
2232
2233 // Manage filter
2234 $errormessage = '';
2235 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
2236 if ($errormessage) {
2237 $this->errors[] = $errormessage;
2238 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2239 return -1;
2240 }
2241
2242 if (!empty($sortfield)) {
2243 $sql .= $this->db->order($sortfield, $sortorder);
2244 }
2245 if (!empty($limit)) {
2246 $sql .= $this->db->plimit($limit, $offset);
2247 }
2248
2249 $resql = $this->db->query($sql);
2250 if ($resql) {
2251 $num = $this->db->num_rows($resql);
2252 $i = 0;
2253 while ($i < ($limit ? min($limit, $num) : $num)) {
2254 $obj = $this->db->fetch_object($resql);
2255
2256 $record = new self($this->db);
2257 $record->setVarsFromFetchObj($obj);
2258
2259 $records[$record->id] = $record;
2260
2261 $i++;
2262 }
2263 $this->db->free($resql);
2264
2265 return $records;
2266 } else {
2267 $this->errors[] = 'Error '.$this->db->lasterror();
2268 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2269
2270 return -1;
2271 }
2272 }
2273
2281 public function update(User $user, $notrigger = 0)
2282 {
2283 return $this->updateCommon($user, $notrigger);
2284 }
2285
2293 public function delete(User $user, $notrigger = 0)
2294 {
2295 return $this->deleteCommon($user, $notrigger);
2296 //return $this->deleteCommon($user, $notrigger, 1);
2297 }
2298}
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:636
$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:253
fetchLinesLinked($role, $lineid=0)
Get list of lines linked to current line for a defined role.
Definition mo.class.php:574
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:470
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:293
fetch($id, $ref=null)
Load object in memory from the database.
Definition mo.class.php:453
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the database.
Definition mo.class.php:490
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:812
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:661
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:695
deleteLine(User $user, $idline, $notrigger=0, $fk_movement=0)
Delete a line of object in database.
Definition mo.class.php:903
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:626
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition mo.class.php:351
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.