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 $this->errors[] = $this->error;
771 break;
772 } else {
773 $moline->fk_product = $line->fk_product;
774 $moline->role = $role;
775 $moline->position = $line->position;
776 $moline->qty_frozen = $line->qty_frozen;
777 $moline->disable_stock_change = $line->disable_stock_change;
778 if (!empty($line->fk_default_workstation)) {
779 $moline->fk_default_workstation = $line->fk_default_workstation;
780 }
781
782 $resultline = $moline->create($user, false); // Never use triggers here
783 if ($resultline <= 0) {
784 $error++;
785 $this->error = $moline->error;
786 $this->errors[] = $moline->error;
787 $this->errors = array_merge($this->errors, $moline->errors);
788 dol_print_error($this->db, $moline->error, $moline->errors);
789 break;
790 }
791 }
792 }
793 }
794 }
795 }
796 }
797
798 if (!$error) {
799 $this->db->commit();
800 return 1;
801 } else {
802 $this->db->rollback();
803 return -1;
804 }
805 }
806
814 public function updateProduction(User $user, $notrigger = 0)
815 {
816 $error = 0;
817
818 if ($this->status != self::STATUS_DRAFT) {
819 return 1;
820 }
821
822 $this->db->begin();
823
824 $oldQty = $this->oldQty;
825 $newQty = $this->qty;
826 if ($newQty != $oldQty && !empty($this->oldQty)) {
827 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "mrp_production WHERE fk_mo = " . (int) $this->id;
828 $resql = $this->db->query($sql);
829 if ($resql) {
830 while ($obj = $this->db->fetch_object($resql)) {
831 $moLine = new MoLine($this->db);
832 $res = $moLine->fetch($obj->rowid);
833 if (!$res) {
834 $error++;
835 }
836
837 if ($moLine->role == 'toconsume' || $moLine->role == 'toproduce') {
838 if (empty($moLine->qty_frozen)) {
839 $qty = $newQty * $moLine->qty / $oldQty;
840 $moLine->qty = (float) price2num($qty, 'MS');
841 $res = $moLine->update($user);
842 if (!$res) {
843 $error++;
844 }
845 }
846 }
847 }
848 }
849 }
850 if (!$error) {
851 $this->db->commit();
852 return 1;
853 } else {
854 $this->db->rollback();
855 return -1;
856 }
857 }
858
859
868 public function delete(User $user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
869 {
870 $error = 0;
871 $this->db->begin();
872
873 if ($also_cancel_consumed_and_produced_lines) {
874 $result = $this->cancelConsumedAndProducedLines($user, 0, false, $notrigger);
875 if ($result < 0) {
876 $error++;
877 }
878 }
879
880 if (!$error) {
881 $result = $this->deleteCommon($user, $notrigger);
882 if ($result < 0) {
883 $error++;
884 }
885 }
886
887 if ($error) {
888 $this->db->rollback();
889 return -1;
890 } else {
891 $this->db->commit();
892 return 1;
893 }
894 }
895
905 public function deleteLine(User $user, $idline, $notrigger = 0, $fk_movement = 0)
906 {
907 global $langs;
908 $langs->loadLangs(array('stocks', 'mrp'));
909
910 if ($this->status < 0) {
911 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
912 return -2;
913 }
914 $productstatic = new Product($this->db);
915
916 $arrayoflines = $this->fetchLinesLinked('consumed', $idline); // Get lines consumed under the one to delete
917
918 $result = 0;
919
920 $this->db->begin();
921
922 if (!empty($arrayoflines)) {
923 // If there is child lines
924 $stockmove = new MouvementStock($this->db);
925 $stockmove->setOrigin($this->element, $this->id);
926
927 if (!empty($fk_movement)) {
928 // The fk_movement was not recorded so we try to guess the product and quantity to restore.
929 $moline = new MoLine($this->db);
930 $TArrayMoLine = $moline->fetchAll('', '', 1, 0, '(fk_stock_movement:=:'.((int) $fk_movement).')');
931 $moline = array_shift($TArrayMoLine);
932
933 $movement = new MouvementStock($this->db);
934 $movement->fetch($fk_movement);
935 $productstatic->fetch($movement->product_id);
936 $qtytoprocess = $movement->qty;
937
938 // Reverse stock movement
939 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
940 $codemovementCancel = $langs->trans("StockIncrease");
941
942 if (($qtytoprocess >= 0)) {
943 $idstockmove = $stockmove->reception($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, '', '', $movement->batch, dol_now(), 0, $codemovementCancel);
944 } else {
945 $idstockmove = $stockmove->livraison($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $movement->batch, 0, $codemovementCancel);
946 }
947 if ($idstockmove < 0) {
948 $this->error++;
949 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
950 } else {
951 $result = $moline->delete($user, $notrigger);
952 }
953 } else {
954 // Loop on each child lines
955 foreach ($arrayoflines as $key => $arrayofline) {
956 $lineDetails = $arrayoflines[$key];
957 $productstatic->fetch($lineDetails['fk_product']);
958 $qtytoprocess = $lineDetails['qty'];
959
960 // Reverse stock movement
961 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
962 $codemovementCancel = $langs->trans("StockIncrease");
963
964
965 if ($qtytoprocess >= 0) {
966 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
967 } else {
968 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
969 }
970 if ($idstockmove < 0) {
971 $this->error++;
972 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
973 } else {
974 $moline = new MoLine($this->db);
975 $moline->fetch($lineDetails['rowid']);
976
977 $resdel = $moline->delete($user, $notrigger);
978 if ($resdel < 0) {
979 $this->error++;
980 setEventMessages($moline->error, $moline->errors, 'errors');
981 }
982 }
983 }
984
985 if (empty($this->error)) {
986 $result = $this->deleteLineCommon($user, $idline, $notrigger);
987 }
988 }
989 } else {
990 // No child lines
991 $result = $this->deleteLineCommon($user, $idline, $notrigger);
992 }
993
994 if (!empty($this->error) || $result <= 0) {
995 $this->db->rollback();
996 } else {
997 $this->db->commit();
998 }
999
1000 return $result;
1001 }
1002
1003
1011 public function getNextNumRef($prod)
1012 {
1013 global $langs, $conf;
1014 $langs->load("mrp");
1015
1016 if (getDolGlobalString('MRP_MO_ADDON')) {
1017 $mybool = false;
1018
1019 $file = getDolGlobalString('MRP_MO_ADDON') . ".php";
1020 $classname = getDolGlobalString('MRP_MO_ADDON');
1021
1022 // Include file with class
1023 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1024 foreach ($dirmodels as $reldir) {
1025 $dir = dol_buildpath($reldir."core/modules/mrp/");
1026
1027 // Load file with numbering class (if found)
1028 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1029 }
1030
1031 if ($mybool === false) {
1032 dol_print_error(null, "Failed to include file ".$file);
1033 return '';
1034 }
1035
1036 $obj = new $classname();
1037 $numref = $obj->getNextValue($prod, $this);
1038
1039 if ($numref != "") {
1040 return $numref;
1041 } else {
1042 $this->error = $obj->error;
1043 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1044 return "";
1045 }
1046 } else {
1047 print $langs->trans("Error")." ".$langs->trans("Error_MRP_MO_ADDON_NotDefined");
1048 return "";
1049 }
1050 }
1051
1059 public function validate($user, $notrigger = 0)
1060 {
1061 global $conf;
1062
1063 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1064
1065 $error = 0;
1066
1067 // Protection
1068 if ($this->status == self::STATUS_VALIDATED) {
1069 dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING);
1070 return 0;
1071 }
1072
1073 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->create))
1074 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mrp->mrp_advance->validate))))
1075 {
1076 $this->error='NotEnoughPermissions';
1077 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
1078 return -1;
1079 }*/
1080
1081 $now = dol_now();
1082
1083 $this->db->begin();
1084
1085 // Define new ref
1086 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1087 $this->fetch_product();
1088 $num = $this->getNextNumRef($this->product);
1089 } else {
1090 $num = $this->ref;
1091 }
1092 $this->newref = $num;
1093
1094 // Validate
1095 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1096 $sql .= " SET ref = '".$this->db->escape($num)."',";
1097 $sql .= " status = ".self::STATUS_VALIDATED.",";
1098 $sql .= " date_valid='".$this->db->idate($now)."',";
1099 $sql .= " fk_user_valid = ".$user->id;
1100 $sql .= " WHERE rowid = ".((int) $this->id);
1101
1102 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
1103 $resql = $this->db->query($sql);
1104 if (!$resql) {
1105 dol_print_error($this->db);
1106 $this->error = $this->db->lasterror();
1107 $error++;
1108 }
1109
1110 if (!$error && !$notrigger) {
1111 // Call trigger
1112 $result = $this->call_trigger('MRP_MO_VALIDATE', $user);
1113 if ($result < 0) {
1114 $error++;
1115 }
1116 // End call triggers
1117 }
1118
1119 if (!$error) {
1120 $this->oldref = $this->ref;
1121
1122 // Rename directory if dir was a temporary ref
1123 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1124 // Now we rename also files into index
1125 $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)."'";
1126 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND 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 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'mrp/".$this->db->escape($this->newref)."'";
1133 $sql .= " WHERE filepath = 'mrp/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1134 $resql = $this->db->query($sql);
1135 if (!$resql) {
1136 $error++;
1137 $this->error = $this->db->lasterror();
1138 }
1139
1140 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1141 $oldref = dol_sanitizeFileName($this->ref);
1142 $newref = dol_sanitizeFileName($num);
1143 $dirsource = $conf->mrp->dir_output.'/'.$oldref;
1144 $dirdest = $conf->mrp->dir_output.'/'.$newref;
1145 if (!$error && file_exists($dirsource)) {
1146 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
1147
1148 if (@rename($dirsource, $dirdest)) {
1149 dol_syslog("Rename ok");
1150 // Rename docs starting with $oldref with $newref
1151 $listoffiles = dol_dir_list($conf->mrp->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1152 foreach ($listoffiles as $fileentry) {
1153 $dirsource = $fileentry['name'];
1154 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1155 $dirsource = $fileentry['path'].'/'.$dirsource;
1156 $dirdest = $fileentry['path'].'/'.$dirdest;
1157 @rename($dirsource, $dirdest);
1158 }
1159 }
1160 }
1161 }
1162 }
1163
1164 // Set new ref and current status
1165 if (!$error) {
1166 $this->ref = $num;
1167 $this->status = self::STATUS_VALIDATED;
1168 }
1169
1170 if (!$error) {
1171 $this->db->commit();
1172 return 1;
1173 } else {
1174 $this->db->rollback();
1175 return -1;
1176 }
1177 }
1178
1186 public function setDraft($user, $notrigger = 0)
1187 {
1188 // Protection
1189 if ($this->status <= self::STATUS_DRAFT) {
1190 return 0;
1191 }
1192
1193 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1194 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1195 {
1196 $this->error='Permission denied';
1197 return -1;
1198 }*/
1199
1200 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'MRP_MO_UNVALIDATE');
1201 }
1202
1211 public function cancel($user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
1212 {
1213 // Protection
1214 if ($this->status != self::STATUS_VALIDATED && $this->status != self::STATUS_INPROGRESS) {
1215 return 0;
1216 }
1217
1218 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1219 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1220 {
1221 $this->error='Permission denied';
1222 return -1;
1223 }*/
1224
1225 $error = 0;
1226 $this->db->begin();
1227
1228 if ($also_cancel_consumed_and_produced_lines) {
1229 $result = $this->cancelConsumedAndProducedLines($user, 0, true, $notrigger);
1230 if ($result < 0) {
1231 $error++;
1232 }
1233 }
1234
1235 if (!$error) {
1236 $result = $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'MRP_MO_CANCEL');
1237 if ($result < 0) {
1238 $error++;
1239 }
1240 }
1241
1242 if ($error) {
1243 $this->db->rollback();
1244 return -1;
1245 } else {
1246 $this->db->commit();
1247 return 1;
1248 }
1249 }
1250
1258 public function reopen($user, $notrigger = 0)
1259 {
1260 // Protection
1261 if ($this->status != self::STATUS_PRODUCED && $this->status != self::STATUS_CANCELED) {
1262 return 0;
1263 }
1264
1265 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->write))
1266 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->mymodule->mymodule_advance->validate))))
1267 {
1268 $this->error='Permission denied';
1269 return -1;
1270 }*/
1271
1272 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'MRP_MO_REOPEN');
1273 }
1274
1284 public function cancelConsumedAndProducedLines($user, $mode = 0, $also_delete_lines = false, $notrigger = 0)
1285 {
1286 global $langs;
1287
1288 if (!isModEnabled('stock')) {
1289 return 1;
1290 }
1291
1292 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1293 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php';
1294 $error = 0;
1295 $langs->load('stocks');
1296
1297 $this->db->begin();
1298
1299 // Cancel consumed lines
1300 if (empty($mode) || $mode == 1) {
1301 $arrayoflines = $this->fetchLinesLinked('consumed');
1302 if (!empty($arrayoflines)) {
1303 foreach ($arrayoflines as $key => $lineDetails) {
1304 $productstatic = new Product($this->db);
1305 $productstatic->fetch($lineDetails['fk_product']);
1306 $qtytoprocess = $lineDetails['qty'];
1307
1308 // Reverse stock movement
1309 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1310 $codemovementCancel = $langs->trans("StockIncrease");
1311
1312 $stockmove = new MouvementStock($this->db);
1313 $stockmove->setOrigin($this->element, $this->id);
1314 if ($qtytoprocess >= 0) {
1315 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1316 } else {
1317 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1318 }
1319 if ($idstockmove < 0) {
1320 $this->error = $stockmove->error;
1321 $this->errors = $stockmove->errors;
1322 $error++;
1323 break;
1324 }
1325
1326 if ($also_delete_lines) {
1327 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1328 if ($result < 0) {
1329 $error++;
1330 break;
1331 }
1332 }
1333 }
1334 }
1335 }
1336
1337 // Cancel produced lines
1338 if (empty($mode) || $mode == 2) {
1339 $arrayoflines = $this->fetchLinesLinked('produced');
1340 if (!empty($arrayoflines)) {
1341 foreach ($arrayoflines as $key => $lineDetails) {
1342 $productstatic = new Product($this->db);
1343 $productstatic->fetch($lineDetails['fk_product']);
1344 $qtytoprocess = $lineDetails['qty'];
1345
1346 // Reverse stock movement
1347 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
1348 $codemovementCancel = $langs->trans("StockDecrease");
1349
1350 $stockmove = new MouvementStock($this->db);
1351 $stockmove->setOrigin($this->element, $this->id);
1352 if ($qtytoprocess >= 0) {
1353 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
1354 } else {
1355 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
1356 }
1357 if ($idstockmove < 0) {
1358 $this->error = $stockmove->error;
1359 $this->errors = $stockmove->errors;
1360 $error++;
1361 break;
1362 }
1363
1364 if ($also_delete_lines) {
1365 $result = $this->deleteLineCommon($user, $lineDetails['rowid'], $notrigger);
1366 if ($result < 0) {
1367 $error++;
1368 break;
1369 }
1370 }
1371 }
1372 }
1373 }
1374
1375 if ($error) {
1376 $this->db->rollback();
1377 return -1;
1378 } else {
1379 $this->db->commit();
1380 return 1;
1381 }
1382 }
1383
1391 public function getTooltipContentArray($params)
1392 {
1393 global $langs;
1394
1395 $langs->loadLangs(['mrp', 'products']);
1396 $nofetch = isset($params['nofetch']) ? true : false;
1397
1398 $datas = [];
1399
1400 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ManufacturingOrder").'</u>';
1401 if (isset($this->status)) {
1402 $datas['picto'] .= ' '.$this->getLibStatut(5);
1403 }
1404 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1405 if (isset($this->label)) {
1406 $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1407 }
1408 if (isset($this->mrptype)) {
1409 $datas['type'] = '<br><b>'.$langs->trans('Type').':</b> '.$this->fields['mrptype']['arrayofkeyval'][$this->mrptype];
1410 }
1411 if (isset($this->qty)) {
1412 $datas['qty'] = '<br><b>'.$langs->trans('QtyToProduce').':</b> '.$this->qty;
1413 }
1414 if (!$nofetch && isset($this->fk_product)) {
1415 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
1416 $product = new Product($this->db);
1417 $product->fetch($this->fk_product);
1418 $datas['product'] = '<br><b>'.$langs->trans('Product').':</b> '.$product->getNomUrl(1, '', 0, -1, 1);
1419 }
1420 if (!$nofetch && isset($this->fk_warehouse)) {
1421 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
1422 $warehouse = new Entrepot($this->db);
1423 $warehouse->fetch($this->fk_warehouse);
1424 $datas['warehouse'] = '<br><b>'.$langs->trans('WarehouseForProduction').':</b> '.$warehouse->getNomUrl(1, '', 0, 1);
1425 }
1426
1427 return $datas;
1428 }
1429
1440 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1441 {
1442 global $conf, $langs, $action, $hookmanager;
1443
1444 if (!empty($conf->dol_no_mouse_hover)) {
1445 $notooltip = 1; // Force disable tooltips
1446 }
1447
1448 $result = '';
1449 $params = [
1450 'id' => $this->id,
1451 'objecttype' => $this->element,
1452 'option' => $option,
1453 'nofetch' => 1,
1454 ];
1455 $classfortooltip = 'classfortooltip';
1456 $dataparams = '';
1457 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1458 $classfortooltip = 'classforajaxtooltip';
1459 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1460 $label = '';
1461 } else {
1462 $label = implode($this->getTooltipContentArray($params));
1463 }
1464
1465 $url = DOL_URL_ROOT.'/mrp/mo_card.php?id='.$this->id;
1466 if ($option == 'production') {
1467 $url = DOL_URL_ROOT.'/mrp/mo_production.php?id='.$this->id;
1468 }
1469
1470 if ($option != 'nolink') {
1471 // Add param to save lastsearch_values or not
1472 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1473 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1474 $add_save_lastsearch_values = 1;
1475 }
1476 if ($add_save_lastsearch_values) {
1477 $url .= '&save_lastsearch_values=1';
1478 }
1479 }
1480
1481 $linkclose = '';
1482 if (empty($notooltip)) {
1483 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1484 $label = $langs->trans("ShowMo");
1485 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1486 }
1487 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1488 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1489 } else {
1490 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1491 }
1492
1493 $linkstart = '<a href="'.$url.'"';
1494 $linkstart .= $linkclose.'>';
1495 $linkend = '</a>';
1496
1497 $result .= $linkstart;
1498 if ($withpicto) {
1499 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
1500 }
1501 if ($withpicto != 2) {
1502 $result .= $this->ref;
1503 }
1504 $result .= $linkend;
1505 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1506
1507 $hookmanager->initHooks(array('modao'));
1508 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1509 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1510 if ($reshook > 0) {
1511 $result = $hookmanager->resPrint;
1512 } else {
1513 $result .= $hookmanager->resPrint;
1514 }
1515
1516 return $result;
1517 }
1518
1525 public function getLibStatut($mode = 0)
1526 {
1527 return $this->LibStatut($this->status, $mode);
1528 }
1529
1530 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1538 public function LibStatut($status, $mode = 0)
1539 {
1540 // phpcs:enable
1541 if (empty($this->labelStatus)) {
1542 global $langs;
1543 //$langs->load("mrp");
1544 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1545 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('ValidatedToProduce');
1546 $this->labelStatus[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1547 $this->labelStatus[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1548 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1549
1550 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1551 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
1552 $this->labelStatusShort[self::STATUS_INPROGRESS] = $langs->transnoentitiesnoconv('InProgress');
1553 $this->labelStatusShort[self::STATUS_PRODUCED] = $langs->transnoentitiesnoconv('StatusMOProduced');
1554 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
1555 }
1556
1557 $statusType = 'status'.$status;
1558 if ($status == self::STATUS_VALIDATED) {
1559 $statusType = 'status1';
1560 }
1561 if ($status == self::STATUS_INPROGRESS) {
1562 $statusType = 'status4';
1563 }
1564 if ($status == self::STATUS_PRODUCED) {
1565 $statusType = 'status6';
1566 }
1567 if ($status == self::STATUS_CANCELED) {
1568 $statusType = 'status9';
1569 }
1570
1571 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1572 }
1573
1580 public function info($id)
1581 {
1582 $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1583 $sql .= ' fk_user_creat, fk_user_modif';
1584 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1585 $sql .= ' WHERE t.rowid = '.((int) $id);
1586 $result = $this->db->query($sql);
1587 if ($result) {
1588 if ($this->db->num_rows($result)) {
1589 $obj = $this->db->fetch_object($result);
1590
1591 $this->id = $obj->rowid;
1592
1593 $this->user_creation_id = $obj->fk_user_creat;
1594 $this->user_modification_id = $obj->fk_user_modif;
1595 $this->date_creation = $this->db->jdate($obj->datec);
1596 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1597 }
1598
1599 $this->db->free($result);
1600 } else {
1601 dol_print_error($this->db);
1602 }
1603 }
1604
1611 public function initAsSpecimen()
1612 {
1613 $ret = $this->initAsSpecimenCommon();
1614
1615 $this->lines = array();
1616
1617 return $ret;
1618 }
1619
1626 public function getLinesArray($rolefilter = '')
1627 {
1628 $this->lines = array();
1629
1630 $objectline = new MoLine($this->db);
1631
1632 $filter = '(fk_mo:=:'.((int) $this->id).')';
1633 if (!empty($rolefilter)) {
1634 $filter .= " AND (role:=:'".$this->db->escape($rolefilter)."')";
1635 }
1636 $result = $objectline->fetchAll('ASC', 'position', 0, 0, $filter);
1637
1638 if (is_numeric($result)) {
1639 $this->error = $objectline->error;
1640 $this->errors = $objectline->errors;
1641 return $result;
1642 } else {
1643 $this->lines = $result;
1644 return $this->lines;
1645 }
1646 }
1647
1659 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1660 {
1661 global $langs;
1662
1663 $langs->load("mrp");
1664
1665 if (!dol_strlen($modele)) {
1666 //$modele = 'standard';
1667 $modele = ''; // Remove this once a pdf_standard.php exists.
1668
1669 if ($this->model_pdf) {
1670 $modele = $this->model_pdf;
1671 } elseif (getDolGlobalString('MRP_MO_ADDON_PDF')) {
1672 $modele = getDolGlobalString('MRP_MO_ADDON_PDF');
1673 }
1674 }
1675
1676 $modelpath = "core/modules/mrp/doc/";
1677
1678 if (empty($modele)) {
1679 return 1; // Remove this once a pdf_standard.php exists.
1680 }
1681
1682 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1683 }
1684
1695 public function printOriginLinesList($restrictlist = '', $selectedLines = array())
1696 {
1697 global $langs, $hookmanager, $form, $action;
1698
1699 $langs->load('stocks');
1700 $text_stock_options = $langs->trans("RealStockDesc").'<br>';
1701 $text_stock_options .= $langs->trans("RealStockWillAutomaticallyWhen").'<br>';
1702 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT') || getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE') ? '- '.$langs->trans("DeStockOnShipment").'<br>' : '');
1703 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_VALIDATE_ORDER') ? '- '.$langs->trans("DeStockOnValidateOrder").'<br>' : '');
1704 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_BILL') ? '- '.$langs->trans("DeStockOnBill").'<br>' : '');
1705 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL') ? '- '.$langs->trans("ReStockOnBill").'<br>' : '');
1706 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER') ? '- '.$langs->trans("ReStockOnValidateOrder").'<br>' : '');
1707 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') ? '- '.$langs->trans("ReStockOnDispatchOrder").'<br>' : '');
1708 $text_stock_options .= (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION') || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE') ? '- '.$langs->trans("StockOnReception").'<br>' : '');
1709
1710 print '<tr class="liste_titre">';
1711 // Product or sub-bom
1712 print '<td class="linecoldescription">'.$langs->trans('Ref');
1713 if (getDolGlobalString('BOM_SUB_BOM')) {
1714 print ' &nbsp; <a id="show_all" href="#">'.img_picto('', 'folder-open', 'class="paddingright"').$langs->trans("ExpandAll").'</a>&nbsp;&nbsp;';
1715 print '<a id="hide_all" href="#">'.img_picto('', 'folder', 'class="paddingright"').$langs->trans("UndoExpandAll").'</a>&nbsp;';
1716 }
1717 print '</td>';
1718 // Qty
1719 print '<td class="right">'.$langs->trans('Qty');
1720 if ($this->bom->bomtype == 0) {
1721 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityOf", $this->bom->qty).')</span>';
1722 } else {
1723 print ' <span class="opacitymedium">('.$langs->trans("ForAQuantityToConsumeOf", $this->bom->qty).')</span>';
1724 }
1725 // Unit
1726 print '<td class="right">'.$langs->trans('Unit');
1727
1728 print '</td>';
1729 print '<td class="center">'.$form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1).'</td>';
1730 print '<td class="center">'.$form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc")).'</td>';
1731 print '<td class="center">'.$langs->trans('QtyFrozen').'</td>';
1732 print '<td class="center">'.$langs->trans('DisableStockChange').'</td>';
1733 print '<td class="center">'.$langs->trans('MoChildGenerate').'</td>';
1734 //print '<td class="center">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
1735 //print '<td class="center"></td>';
1736 print '</tr>';
1737 $i = 0;
1738
1739 if (!empty($this->lines)) {
1740 foreach ($this->lines as $line) {
1741 $reshook = 0;
1742 if (is_object($hookmanager)) {
1743 $parameters = array('line' => $line, 'i' => $i, 'restrictlist' => $restrictlist, 'selectedLines' => $selectedLines);
1744 if (!empty($line->fk_parent_line)) {
1745 $parameters['fk_parent_line'] = $line->fk_parent_line;
1746 }
1747 $reshook = $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1748 }
1749 if (empty($reshook)) {
1750 $this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
1751 }
1752
1753 $i++;
1754 }
1755 }
1756 }
1757
1758
1772 public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
1773 {
1774 $productstatic = new Product($this->db);
1775
1776 $this->tpl['id'] = $line->id;
1777
1778 $this->tpl['label'] = '';
1779 if (!empty($line->fk_product) && $line->fk_product > 0) {
1780 $productstatic->fetch($line->fk_product);
1781 $productstatic->load_virtual_stock();
1782 $this->tpl['label'] .= $productstatic->getNomUrl(1);
1783 //$this->tpl['label'].= ' - '.$productstatic->label;
1784 } else {
1785 // If origin MO line is not a product, but another MO
1786 // TODO
1787 }
1788
1789 $this->tpl['qty_bom'] = 1;
1790 if (is_object($this->bom) && $this->bom->qty > 1) {
1791 $this->tpl['qty_bom'] = $this->bom->qty;
1792 }
1793
1794 $this->tpl['stock'] = $productstatic->stock_reel;
1795 $this->tpl['seuil_stock_alerte'] = $productstatic->seuil_stock_alerte;
1796 $this->tpl['virtual_stock'] = $productstatic->stock_theorique;
1797 $this->tpl['qty'] = $line->qty;
1798 $this->tpl['fk_unit'] = $line->fk_unit;
1799 $this->tpl['qty_frozen'] = $line->qty_frozen;
1800 $this->tpl['disable_stock_change'] = $line->disable_stock_change;
1801 $this->tpl['efficiency'] = $line->efficiency;
1802
1803 global $conf; // used into template
1804 $res = include DOL_DOCUMENT_ROOT.'/mrp/tpl/originproductline.tpl.php';
1805 }
1806
1815 public static function replaceThirdparty($db, $origin_id, $dest_id)
1816 {
1817 $tables = array('mrp_mo');
1818
1819 return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1820 }
1821
1822
1828 public function getMoChilds()
1829 {
1830 $TMoChilds = array();
1831 $error = 0;
1832
1833 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_mo as mo_child";
1834 $sql .= " WHERE fk_parent_line IN ";
1835 $sql .= " (SELECT rowid FROM ".MAIN_DB_PREFIX."mrp_production as line_parent";
1836 $sql .= " WHERE fk_mo=".((int) $this->id).")";
1837
1838 $resql = $this->db->query($sql);
1839
1840 if ($resql) {
1841 if ($this->db->num_rows($resql) > 0) {
1842 while ($obj = $this->db->fetch_object($resql)) {
1843 $MoChild = new Mo($this->db);
1844 $res = $MoChild->fetch($obj->rowid);
1845 if ($res > 0) {
1846 $TMoChilds[$MoChild->id] = $MoChild;
1847 } else {
1848 $error++;
1849 }
1850 }
1851 }
1852 } else {
1853 $error++;
1854 }
1855
1856 if ($error) {
1857 return -1;
1858 } else {
1859 return $TMoChilds;
1860 }
1861 }
1862
1869 public function getAllMoChilds($depth = 0)
1870 {
1871 if ($depth > 1000) {
1872 return -1;
1873 }
1874
1875 $TMoChilds = array();
1876 $error = 0;
1877
1878 $childMoList = $this->getMoChilds();
1879
1880 if ($childMoList == -1) {
1881 return -1;
1882 }
1883
1884 foreach ($childMoList as $childMo) {
1885 $TMoChilds[$childMo->id] = $childMo;
1886 }
1887
1888 foreach ($childMoList as $childMo) {
1889 $childMoChildren = $childMo->getAllMoChilds($depth + 1);
1890
1891 if ($childMoChildren == -1) {
1892 $error++;
1893 } else {
1894 foreach ($childMoChildren as $child) {
1895 $TMoChilds[$child->id] = $child;
1896 }
1897 }
1898 }
1899
1900 if ($error) {
1901 return -1;
1902 } else {
1903 return $TMoChilds;
1904 }
1905 }
1906
1907
1908
1914 public function getMoParent()
1915 {
1916 $MoParent = new Mo($this->db);
1917 $error = 0;
1918
1919 $sql = "SELECT lineparent.fk_mo as id_moparent FROM ".MAIN_DB_PREFIX."mrp_mo as mo";
1920 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."mrp_production lineparent ON mo.fk_parent_line = lineparent.rowid";
1921 $sql .= " WHERE mo.rowid = ".((int) $this->id);
1922
1923 $resql = $this->db->query($sql);
1924
1925 if ($resql) {
1926 if ($this->db->num_rows($resql) > 0) {
1927 $obj = $this->db->fetch_object($resql);
1928 $res = $MoParent->fetch($obj->id_moparent);
1929 if ($res < 0) {
1930 $error++;
1931 }
1932 } else {
1933 return 0;
1934 }
1935 } else {
1936 $error++;
1937 }
1938
1939 if ($error) {
1940 return -1;
1941 } else {
1942 return $MoParent;
1943 }
1944 }
1945
1953 public function getKanbanView($option = '', $arraydata = null)
1954 {
1955 global $langs;
1956
1957 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1958
1959 $return = '<div class="box-flex-item box-flex-grow-zero">';
1960 $return .= '<div class="info-box info-box-sm">';
1961 $return .= '<span class="info-box-icon bg-infobox-action">';
1962 $return .= img_picto('', $this->picto);
1963 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
1964 $return .= '</span>';
1965 $return .= '<div class="info-box-content">';
1966 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
1967 if ($selected >= 0) {
1968 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1969 }
1970 if (!empty($arraydata['bom'])) {
1971 $return .= '<br><span class="info-box-label">'.$arraydata['bom']->getNomUrl(1).'</span>';
1972 }
1973 if (!empty($arraydata['product'])) {
1974 $return .= '<br><span class="info-box-label">'.$arraydata['product']->getNomUrl(1).'</span>';
1975 if (property_exists($this, 'qty')) {
1976 $return .= ' <span class="info-box-label">('.$langs->trans("Qty").' '.$this->qty.')</span>';
1977 }
1978 } else {
1979 if (property_exists($this, 'qty')) {
1980 $return .= '<br><span class="info-box-label">'.$langs->trans('Quantity').' : '.$this->qty.'</span>';
1981 }
1982 }
1983 if (method_exists($this, 'getLibStatut')) {
1984 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
1985 }
1986 $return .= '</div>';
1987 $return .= '</div>';
1988 $return .= '</div>';
1989 return $return;
1990 }
1991}
1992
1993
1998{
2002 public $element = 'mrp_production';
2003
2007 public $table_element = 'mrp_production';
2008
2012 public $parent_element = 'mo';
2013
2017 public $fk_parent_attribute = 'fk_mo';
2018
2059 public $fields = array(
2060 'rowid' => array('type' => 'integer', 'label' => 'ID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
2061 'fk_mo' => array('type' => 'integer', 'label' => 'Mo', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 15),
2062 'origin_id' => array('type' => 'integer', 'label' => 'Origin', 'enabled' => 1, 'visible' => -1, 'notnull' => 0, 'position' => 17),
2063 'origin_type' => array('type' => 'varchar(10)', 'label' => 'Origin type', 'enabled' => 1, 'visible' => -1, 'notnull' => 0, 'position' => 18),
2064 'position' => array('type' => 'integer', 'label' => 'Position', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 20),
2065 'fk_product' => array('type' => 'integer', 'label' => 'Product', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 25),
2066 'fk_warehouse' => array('type' => 'integer', 'label' => 'Warehouse', 'enabled' => 1, 'visible' => -1, 'position' => 30),
2067 'qty' => array('type' => 'real', 'label' => 'Qty', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35),
2068 'qty_frozen' => array('type' => 'smallint', 'label' => 'QuantityFrozen', 'enabled' => 1, 'visible' => 1, 'default' => '0', 'notnull' => 1, 'position' => 105, 'css' => 'maxwidth50imp', 'help' => 'QuantityConsumedInvariable'),
2069 'disable_stock_change' => array('type' => 'smallint', 'label' => 'DisableStockChange', 'enabled' => 1, 'visible' => 1, 'default' => '0', 'notnull' => 1, 'position' => 108, 'css' => 'maxwidth50imp', 'help' => 'DisableStockChangeHelp'),
2070 'batch' => array('type' => 'varchar(30)', 'label' => 'Batch', 'enabled' => 1, 'visible' => -1, 'position' => 140),
2071 'role' => array('type' => 'varchar(10)', 'label' => 'Role', 'enabled' => 1, 'visible' => -1, 'position' => 145),
2072 'fk_mrp_production' => array('type' => 'integer', 'label' => 'Fk mrp production', 'enabled' => 1, 'visible' => -1, 'position' => 150),
2073 'fk_stock_movement' => array('type' => 'integer', 'label' => 'StockMovement', 'enabled' => 1, 'visible' => -1, 'position' => 155),
2074 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 160),
2075 'tms' => array('type' => 'timestamp', 'label' => 'Tms', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 165),
2076 'fk_user_creat' => array('type' => 'integer', 'label' => 'UserCreation', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 170),
2077 'fk_user_modif' => array('type' => 'integer', 'label' => 'UserModification', 'enabled' => 1, 'visible' => -1, 'position' => 175),
2078 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -1, 'position' => 180),
2079 'fk_default_workstation' => array('type' => 'integer', 'label' => 'DefaultWorkstation', 'enabled' => 1, 'visible' => 1, 'notnull' => 0, 'position' => 185),
2080 'fk_unit' => array('type' => 'int', 'label' => 'Unit', 'enabled' => 1, 'visible' => 1, 'notnull' => 0, 'position' => 186)
2081 );
2082
2083 public $rowid;
2084 public $fk_mo;
2085 public $origin_id;
2086 public $origin_type;
2087 public $position;
2088 public $fk_product;
2089 public $fk_warehouse;
2090
2094 public $qty;
2095
2099 public $qty_frozen;
2100 public $disable_stock_change;
2101 public $efficiency;
2102 public $batch;
2103 public $role;
2104 public $fk_mrp_production;
2105 public $fk_stock_movement;
2106 public $date_creation;
2107 public $fk_user_creat;
2108 public $fk_user_modif;
2109 public $import_key;
2110 public $fk_parent_line;
2111 public $fk_unit;
2112
2116 public $fk_default_workstation;
2117
2123 public function __construct(DoliDB $db)
2124 {
2125 global $langs;
2126
2127 $this->db = $db;
2128
2129 $this->ismultientitymanaged = 0;
2130 $this->isextrafieldmanaged = 1;
2131
2132 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
2133 $this->fields['rowid']['visible'] = 0;
2134 }
2135 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
2136 $this->fields['entity']['enabled'] = 0;
2137 }
2138
2139 // Unset fields that are disabled
2140 foreach ($this->fields as $key => $val) {
2141 if (isset($val['enabled']) && empty($val['enabled'])) {
2142 unset($this->fields[$key]);
2143 }
2144 }
2145
2146 // Translate some data of arrayofkeyval
2147 if (is_object($langs)) {
2148 foreach ($this->fields as $key => $val) {
2149 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
2150 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
2151 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
2152 }
2153 }
2154 }
2155 }
2156 }
2157
2165 public function create(User $user, $notrigger = 0)
2166 {
2167 if (empty($this->qty)) {
2168 $this->error = 'ErrorEmptyValueForQty';
2169 return -1;
2170 }
2171
2172 return $this->createCommon($user, $notrigger);
2173 }
2174
2182 public function fetch($id, $ref = null)
2183 {
2184 $result = $this->fetchCommon($id, $ref);
2185 return $result;
2186 }
2187
2199 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
2200 {
2201 dol_syslog(__METHOD__, LOG_DEBUG);
2202
2203 $records = array();
2204
2205 $sql = 'SELECT ';
2206 $sql .= $this->getFieldList();
2207 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
2208 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
2209 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
2210 } else {
2211 $sql .= ' WHERE 1 = 1';
2212 }
2213
2214 // Deprecated.
2215 if (is_array($filter)) {
2216 $sqlwhere = array();
2217 if (count($filter) > 0) {
2218 foreach ($filter as $key => $value) {
2219 if ($key == 't.rowid') {
2220 $sqlwhere[] = $key." = ".((int) $value);
2221 } elseif (strpos($key, 'date') !== false) {
2222 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
2223 } else {
2224 $sqlwhere[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
2225 }
2226 }
2227 }
2228 if (count($sqlwhere) > 0) {
2229 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
2230 }
2231
2232 $filter = '';
2233 }
2234
2235 // Manage filter
2236 $errormessage = '';
2237 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
2238 if ($errormessage) {
2239 $this->errors[] = $errormessage;
2240 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2241 return -1;
2242 }
2243
2244 if (!empty($sortfield)) {
2245 $sql .= $this->db->order($sortfield, $sortorder);
2246 }
2247 if (!empty($limit)) {
2248 $sql .= $this->db->plimit($limit, $offset);
2249 }
2250
2251 $resql = $this->db->query($sql);
2252 if ($resql) {
2253 $num = $this->db->num_rows($resql);
2254 $i = 0;
2255 while ($i < ($limit ? min($limit, $num) : $num)) {
2256 $obj = $this->db->fetch_object($resql);
2257
2258 $record = new self($this->db);
2259 $record->setVarsFromFetchObj($obj);
2260
2261 $records[$record->id] = $record;
2262
2263 $i++;
2264 }
2265 $this->db->free($resql);
2266
2267 return $records;
2268 } else {
2269 $this->errors[] = 'Error '.$this->db->lasterror();
2270 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2271
2272 return -1;
2273 }
2274 }
2275
2283 public function update(User $user, $notrigger = 0)
2284 {
2285 return $this->updateCommon($user, $notrigger);
2286 }
2287
2295 public function delete(User $user, $notrigger = 0)
2296 {
2297 return $this->deleteCommon($user, $notrigger);
2298 //return $this->deleteCommon($user, $notrigger, 1);
2299 }
2300}
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:637
$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:814
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:905
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.