dolibarr 20.0.5
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 * Copyright (C) 2025 Noé Cendrier <noe.cendrier@altairis.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
28// Put here all includes required by your class file
29require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
30require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
31
32
36class Mo extends CommonObject
37{
41 public $element = 'mo';
42
46 public $table_element = 'mrp_mo';
47
51 public $picto = 'mrp';
52
53
54 const STATUS_DRAFT = 0;
55 const STATUS_VALIDATED = 1; // To produce
56 const STATUS_INPROGRESS = 2;
57 const STATUS_PRODUCED = 3;
58 const STATUS_CANCELED = 9;
59
60
90 public $fields = array(
91 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -2, 'position' => 1, 'notnull' => 1, 'index' => 1, 'comment' => "Id",),
92 'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'position' => 5, 'notnull' => 1, 'default' => '1', 'index' => 1),
93 '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),
94 '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'),
95 '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'),
96 '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'),
97 'qty' => array('type' => 'real', 'label' => 'QtyToProduce', 'enabled' => 1, 'visible' => 1, 'position' => 40, 'notnull' => 1, 'comment' => "Qty to produce", 'css' => 'width75', 'default' => '1', 'isameasure' => 1),
98 '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),
99 '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'),
100 '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'),
101 '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'),
102 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 61, 'notnull' => -1,),
103 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 62, 'notnull' => -1,),
104 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'position' => 500, 'notnull' => 1,),
105 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'position' => 501, 'notnull' => 1,),
106 'date_valid' => array('type' => 'datetime', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -2, 'position' => 502,),
107 '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'),
108 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'position' => 511, 'notnull' => -1, 'csslist' => 'tdoverflowmax100'),
109 'date_start_planned' => array('type' => 'datetime', 'label' => 'DateStartPlannedMo', 'enabled' => 1, 'visible' => 1, 'position' => 55, 'notnull' => -1, 'index' => 1, 'help' => 'KeepEmptyForAsap', 'alwayseditable' => 1, 'csslist' => 'nowraponall'),
110 'date_end_planned' => array('type' => 'datetime', 'label' => 'DateEndPlannedMo', 'enabled' => 1, 'visible' => 1, 'position' => 56, 'notnull' => -1, 'index' => 1, 'alwayseditable' => 1, 'csslist' => 'nowraponall'),
111 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 1000, 'notnull' => -1,),
112 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'visible' => 0, 'position' => 1010),
113 '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')),
114 '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),
115 );
116 public $rowid;
117 public $entity;
118 public $ref;
119
123 public $mrptype;
124 public $label;
125
129 public $qty;
130 public $fk_warehouse;
131 public $fk_soc;
132 public $socid;
133
137 public $note_public;
138
142 public $note_private;
143
147 public $date_creation;
148
152 public $date_valid;
153
154 public $fk_user_creat;
155 public $fk_user_modif;
156 public $import_key;
157 public $status;
158
162 public $fk_product;
163
167 public $product;
168
172 public $date_start_planned;
173
177 public $date_end_planned;
178
182 public $fk_bom;
183
187 public $bom;
188
192 public $fk_project;
193
198 public $oldQty;
199
200
201 // If this object has a subtable with lines
202
206 public $table_element_line = 'mrp_production';
207
211 public $fk_element = 'fk_mo';
212
216 public $class_element_line = 'MoLine';
217
221 protected $childtables = array();
222
226 protected $childtablesoncascade = array('mrp_production');
227
231 public $lines = array();
232
236 public $line = null;
237
241 public $fk_parent_line;
242
246 public $tpl = array();
247
248
254 public function __construct(DoliDB $db)
255 {
256 global $langs;
257
258 $this->db = $db;
259
260 $this->ismultientitymanaged = 1;
261 $this->isextrafieldmanaged = 1;
262
263 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
264 $this->fields['rowid']['visible'] = 0;
265 }
266 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
267 $this->fields['entity']['enabled'] = 0;
268 }
269
270 // Unset fields that are disabled
271 foreach ($this->fields as $key => $val) {
272 if (isset($val['enabled']) && empty($val['enabled'])) {
273 unset($this->fields[$key]);
274 }
275 }
276
277 // Translate some data of arrayofkeyval
278 foreach ($this->fields as $key => $val) {
279 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
280 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
281 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
282 }
283 }
284 }
285 }
286
294 public function create(User $user, $notrigger = 0)
295 {
296 $error = 0;
297 $idcreated = 0;
298
299 // 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
300 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && !getDolGlobalString('ALLOW_USE_KITS_INTO_BOM_AND_MO') && $this->fk_product > 0) {
301 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
302 $tmpproduct = new Product($this->db);
303 $tmpproduct->fetch($this->fk_product);
304 if ($tmpproduct->hasFatherOrChild(1) > 0) {
305 $this->error = 'ErrorAVirtualProductCantBeUsedIntoABomOrMo';
306 $this->errors[] = $this->error;
307 return -1;
308 }
309 }
310
311 $this->db->begin();
312
313 if ($this->fk_bom > 0) {
314 // If there is a known BOM, we force the type of MO to the type of BOM
315 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
316 $tmpbom = new BOM($this->db);
317 $tmpbom->fetch($this->fk_bom);
318
319 $this->mrptype = $tmpbom->bomtype;
320 }
321
322 if (!$error) {
323 $idcreated = $this->createCommon($user, $notrigger);
324 if ($idcreated <= 0) {
325 $error++;
326 }
327 }
328
329 if (!$error) {
330 $result = $this->createProduction($user, $notrigger); // Insert lines from BOM
331 if ($result <= 0) {
332 $error++;
333 }
334 }
335
336 if (!$error) {
337 $this->db->commit();
338 return $idcreated;
339 } else {
340 $this->db->rollback();
341 return -1;
342 }
343 }
344
352 public function createFromClone(User $user, $fromid)
353 {
354 global $langs, $extrafields;
355 $error = 0;
356
357 dol_syslog(__METHOD__, LOG_DEBUG);
358
359 $object = new self($this->db);
360
361 $this->db->begin();
362
363 // Load source object
364 $result = $object->fetchCommon($fromid);
365 if ($result > 0 && !empty($object->table_element_line)) {
366 $object->fetchLines();
367 }
368
369 // get lines so they will be clone
370 //foreach($this->lines as $line)
371 // $line->fetch_optionals();
372
373 // Reset some properties
374 unset($object->id);
375 unset($object->fk_user_creat);
376 unset($object->import_key);
377
378 // We make $object->lines empty to sort it without produced and consumed lines
379 $TLines = $object->lines;
380 $object->lines = array();
381
382 // Remove produced and consumed lines
383 foreach ($TLines as $key => $line) {
384 if (in_array($line->role, array('consumed', 'produced'))) {
385 unset($object->lines[$key]);
386 } else {
387 $object->lines[] = $line;
388 }
389 }
390
391
392 // Clear fields
393 $object->ref = empty($this->fields['ref']['default']) ? "copy_of_".$object->ref : $this->fields['ref']['default'];
394 $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
395 $object->status = self::STATUS_DRAFT;
396 // ...
397 // Clear extrafields that are unique
398 if (is_array($object->array_options) && count($object->array_options) > 0) {
399 $extrafields->fetch_name_optionals_label($this->table_element);
400 foreach ($object->array_options as $key => $option) {
401 $shortkey = preg_replace('/options_/', '', $key);
402 if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
403 //var_dump($key);
404 //var_dump($clonedObj->array_options[$key]); exit;
405 unset($object->array_options[$key]);
406 }
407 }
408 }
409
410 // Create clone
411 $object->context['createfromclone'] = 'createfromclone';
412 $result = $object->createCommon($user);
413 if ($result < 0) {
414 $error++;
415 $this->error = $object->error;
416 $this->errors = $object->errors;
417 }
418
419 if (!$error) {
420 // copy internal contacts
421 if ($this->copy_linked_contact($object, 'internal') < 0) {
422 $error++;
423 }
424 }
425
426 if (!$error) {
427 // copy external contacts if same company
428 if (property_exists($this, 'socid') && $this->socid == $object->socid) {
429 if ($this->copy_linked_contact($object, 'external') < 0) {
430 $error++;
431 }
432 }
433 }
434
435 unset($object->context['createfromclone']);
436
437 // End
438 if (!$error) {
439 $this->db->commit();
440 return $object;
441 } else {
442 $this->db->rollback();
443 return -1;
444 }
445 }
446
454 public function fetch($id, $ref = null)
455 {
456 $result = $this->fetchCommon($id, $ref);
457 if ($result > 0 && !empty($this->table_element_line)) {
458 $this->fetchLines();
459 }
460
461 $this->socid = $this->fk_soc;
462
463 return $result;
464 }
465
471 public function fetchLines()
472 {
473 $this->lines = array();
474
475 $result = $this->fetchLinesCommon();
476 return $result;
477 }
478
479
491 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
492 {
493 dol_syslog(__METHOD__, LOG_DEBUG);
494
495 $records = array();
496
497 $sql = 'SELECT ';
498 $sql .= $this->getFieldList();
499 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
500 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
501 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
502 } else {
503 $sql .= ' WHERE 1 = 1';
504 }
505
506 // Manage filter
507 if (is_array($filter)) {
508 $sqlwhere = array();
509 if (count($filter) > 0) {
510 foreach ($filter as $key => $value) {
511 if ($key == 't.rowid') {
512 $sqlwhere[] = $this->db->sanitize($key)." = ".((int) $value);
513 } elseif (strpos($key, 'date') !== false) {
514 $sqlwhere[] = $this->db->sanitize($key)." = '".$this->db->idate($value)."'";
515 } else {
516 $sqlwhere[] = $this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
517 }
518 }
519 }
520 if (count($sqlwhere) > 0) {
521 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
522 }
523
524 $filter = '';
525 }
526
527 // Manage filter
528 $errormessage = '';
529 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
530 if ($errormessage) {
531 $this->errors[] = $errormessage;
532 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
533 return -1;
534 }
535
536 if (!empty($sortfield)) {
537 $sql .= $this->db->order($sortfield, $sortorder);
538 }
539 if (!empty($limit)) {
540 $sql .= $this->db->plimit($limit, $offset);
541 }
542
543 $resql = $this->db->query($sql);
544 if ($resql) {
545 $num = $this->db->num_rows($resql);
546 $i = 0;
547 while ($i < min($limit, $num)) {
548 $obj = $this->db->fetch_object($resql);
549
550 $record = new self($this->db);
551 $record->setVarsFromFetchObj($obj);
552
553 $records[$record->id] = $record;
554
555 $i++;
556 }
557 $this->db->free($resql);
558
559 return $records;
560 } else {
561 $this->errors[] = 'Error '.$this->db->lasterror();
562 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
563
564 return -1;
565 }
566 }
567
575 public function fetchLinesLinked($role, $lineid = 0)
576 {
577 $resarray = array();
578 $mostatic = new MoLine($this->db);
579
580 $sql = 'SELECT ';
581 $sql .= $mostatic->getFieldList();
582 $sql .= ' FROM '.MAIN_DB_PREFIX.$mostatic->table_element.' as t';
583 $sql .= " WHERE t.role = '".$this->db->escape($role)."'";
584 if ($lineid > 0) {
585 $sql .= ' AND t.fk_mrp_production = '.((int) $lineid);
586 } else {
587 $sql .= 'AND t.fk_mo = '.((int) $this->id);
588 }
589
590 $resql = $this->db->query($sql);
591 if ($resql) {
592 $num = $this->db->num_rows($resql);
593
594 $i = 0;
595 while ($i < $num) {
596 $obj = $this->db->fetch_object($resql);
597 if ($obj) {
598 $resarray[] = array(
599 'rowid' => $obj->rowid,
600 'date' => $this->db->jdate($obj->date_creation),
601 'qty' => $obj->qty,
602 'role' => $obj->role,
603 'fk_product' => $obj->fk_product,
604 'fk_warehouse' => $obj->fk_warehouse,
605 'batch' => $obj->batch,
606 'fk_stock_movement' => $obj->fk_stock_movement,
607 'fk_unit' => $obj->fk_unit
608 );
609 }
610
611 $i++;
612 }
613
614 return $resarray;
615 } else {
616 $this->error = $this->db->lasterror();
617 return array();
618 }
619 }
620
621
627 public function countMovements()
628 {
629 $result = 0;
630
631 $sql = 'SELECT COUNT(rowid) as nb FROM '.MAIN_DB_PREFIX.'stock_mouvement as sm';
632 $sql .= " WHERE sm.origintype = 'mo' and sm.fk_origin = ".((int) $this->id);
633
634 $resql = $this->db->query($sql);
635 if ($resql) {
636 $num = $this->db->num_rows($resql);
637
638 $i = 0;
639 while ($i < $num) {
640 $obj = $this->db->fetch_object($resql);
641 if ($obj) {
642 $result = $obj->nb;
643 }
644
645 $i++;
646 }
647 } else {
648 $this->error = $this->db->lasterror();
649 }
650
651 return $result;
652 }
653
654
662 public function update(User $user, $notrigger = 0)
663 {
664 $error = 0;
665
666 $this->db->begin();
667
668 $result = $this->updateCommon($user, $notrigger);
669 if ($result <= 0) {
670 $error++;
671 }
672
673 // Update the lines (the qty) to consume or to produce
674 $result = $this->updateProduction($user, $notrigger);
675 if ($result <= 0) {
676 $error++;
677 }
678
679 if (!$error) {
680 $this->db->commit();
681 return 1;
682 } else {
683 $this->db->rollback();
684 return -1;
685 }
686 }
687
688
696 public function createProduction(User $user, $notrigger = 0)
697 {
698 $error = 0;
699 $role = "";
700
701 if ($this->status != self::STATUS_DRAFT) {
702 return -1;
703 }
704
705 $this->db->begin();
706
707 // Insert lines in mrp_production table from BOM data
708 if (!$error) {
709 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'mrp_production WHERE fk_mo = '.((int) $this->id);
710 $this->db->query($sql);
711
712 $moline = new MoLine($this->db);
713
714 // Line to produce
715 $moline->fk_mo = $this->id;
716 $moline->qty = $this->qty;
717 $moline->fk_product = $this->fk_product;
718 $moline->position = 1;
719 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
720 $tmpproduct = new Product($this->db);
721 $tmpproduct->fetch($this->fk_product);
722 $moline->fk_unit = $tmpproduct->fk_unit;
723
724 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to produce.
725 include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
726 $bom = new BOM($this->db);
727 $bom->fetch($this->fk_bom);
728 if ($bom->bomtype == 1) {
729 $role = 'toproduce';
730 $moline->role = 'toconsume';
731 } else {
732 $role = 'toconsume';
733 $moline->role = 'toproduce';
734 }
735 } else {
736 if ($this->mrptype == 1) {
737 $moline->role = 'toconsume';
738 } else {
739 $moline->role = 'toproduce';
740 }
741 }
742
743 $resultline = $moline->create($user, false); // Never use triggers here
744 if ($resultline <= 0) {
745 $error++;
746 $this->error = $moline->error;
747 $this->errors = $moline->errors;
748 }
749
750 if ($this->fk_bom > 0) { // If a BOM is defined, we know what to consume.
751 if ($bom->id > 0) {
752 // Lines to consume
753 if (!$error) {
754 foreach ($bom->lines as $line) {
755 $moline = new MoLine($this->db);
756
757 $moline->fk_mo = $this->id;
758 $moline->origin_id = $line->id;
759 $moline->origin_type = 'bomline';
760 if (!empty($line->fk_unit)) {
761 $moline->fk_unit = $line->fk_unit;
762 }
763 if ($line->qty_frozen) {
764 $moline->qty = $line->qty; // Qty to consume does not depends on quantity to produce
765 } else {
766 $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
767 }
768 if ($moline->qty <= 0) {
769 $error++;
770 $this->error = "BadValueForquantityToConsume";
771 $this->errors[] = $this->error;
772 break;
773 } else {
774 $moline->fk_product = $line->fk_product;
775 $moline->role = $role;
776 $moline->position = $line->position;
777 $moline->qty_frozen = $line->qty_frozen;
778 $moline->disable_stock_change = $line->disable_stock_change;
779 if (!empty($line->fk_default_workstation)) {
780 $moline->fk_default_workstation = $line->fk_default_workstation;
781 }
782
783 $resultline = $moline->create($user, false); // Never use triggers here
784 if ($resultline <= 0) {
785 $error++;
786 $this->error = $moline->error;
787 $this->errors[] = $moline->error;
788 $this->errors = array_merge($this->errors, $moline->errors);
789 dol_print_error($this->db, $moline->error, $moline->errors);
790 break;
791 }
792 }
793 }
794 }
795 }
796 }
797 }
798
799 if (!$error) {
800 $this->db->commit();
801 return 1;
802 } else {
803 $this->db->rollback();
804 return -1;
805 }
806 }
807
815 public function updateProduction(User $user, $notrigger = 0)
816 {
817 $error = 0;
818
819 if ($this->status != self::STATUS_DRAFT) {
820 return 1;
821 }
822
823 $this->db->begin();
824
825 $oldQty = $this->oldQty;
826 $newQty = $this->qty;
827 if ($newQty != $oldQty && !empty($this->oldQty)) {
828 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "mrp_production WHERE fk_mo = " . (int) $this->id;
829 $resql = $this->db->query($sql);
830 if ($resql) {
831 while ($obj = $this->db->fetch_object($resql)) {
832 $moLine = new MoLine($this->db);
833 $res = $moLine->fetch($obj->rowid);
834 if (!$res) {
835 $error++;
836 }
837
838 if ($moLine->role == 'toconsume' || $moLine->role == 'toproduce') {
839 if (empty($moLine->qty_frozen)) {
840 $qty = $newQty * $moLine->qty / $oldQty;
841 $moLine->qty = (float) price2num($qty, 'MS');
842 $res = $moLine->update($user);
843 if (!$res) {
844 $error++;
845 }
846 }
847 }
848 }
849 }
850 }
851 if (!$error) {
852 $this->db->commit();
853 return 1;
854 } else {
855 $this->db->rollback();
856 return -1;
857 }
858 }
859
860
869 public function delete(User $user, $notrigger = 0, $also_cancel_consumed_and_produced_lines = false)
870 {
871 $error = 0;
872 $this->db->begin();
873
874 if ($also_cancel_consumed_and_produced_lines) {
875 $result = $this->cancelConsumedAndProducedLines($user, 0, false, $notrigger);
876 if ($result < 0) {
877 $error++;
878 }
879 }
880
881 if (!$error) {
882 $result = $this->deleteCommon($user, $notrigger);
883 if ($result < 0) {
884 $error++;
885 }
886 }
887
888 if ($error) {
889 $this->db->rollback();
890 return -1;
891 } else {
892 $this->db->commit();
893 return 1;
894 }
895 }
896
906 public function deleteLine(User $user, $idline, $notrigger = 0, $fk_movement = 0)
907 {
908 global $langs;
909 $langs->loadLangs(array('stocks', 'mrp'));
910
911 if ($this->status < 0) {
912 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
913 return -2;
914 }
915 $productstatic = new Product($this->db);
916
917 $arrayoflines = $this->fetchLinesLinked('consumed', $idline); // Get lines consumed under the one to delete
918
919 $result = 0;
920
921 $this->db->begin();
922
923 if (!empty($fk_movement) || !empty($arrayoflines)) {
924 $stockmove = new MouvementStock($this->db);
925 $stockmove->setOrigin($this->element, $this->id);
926 }
927
928 if (!empty($fk_movement)) {
929 // The fk_movement was not recorded so we try to guess the product and quantity to restore.
930 $moline = new MoLine($this->db);
931 $TArrayMoLine = $moline->fetchAll('', '', 1, 0, '(fk_stock_movement:=:'.((int) $fk_movement).')');
932 $moline = array_shift($TArrayMoLine);
933
934 $movement = new MouvementStock($this->db);
935 $movement->fetch($fk_movement);
936 $productstatic->fetch($movement->product_id);
937 $qtytoprocess = $movement->qty;
938
939 // Reverse stock movement
940 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
941 $codemovementCancel = $langs->trans("StockIncrease");
942
943 if (($qtytoprocess >= 0)) {
944 $idstockmove = $stockmove->reception($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, '', '', $movement->batch, dol_now(), 0, $codemovementCancel);
945 } else {
946 $idstockmove = $stockmove->livraison($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $movement->batch, 0, $codemovementCancel);
947 }
948 if ($idstockmove < 0) {
949 $this->error++;
950 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
951 } else {
952 $result = $moline->delete($user, $notrigger);
953 }
954 } elseif (!empty($arrayoflines)) {
955 // Loop on each child lines
956 foreach ($arrayoflines as $key => $arrayofline) {
957 $lineDetails = $arrayoflines[$key];
958 $productstatic->fetch($lineDetails['fk_product']);
959 $qtytoprocess = $lineDetails['qty'];
960
961 // Reverse stock movement
962 $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
963 $codemovementCancel = $langs->trans("StockIncrease");
964
965
966 if ($qtytoprocess >= 0) {
967 $idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
968 } else {
969 $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
970 }
971 if ($idstockmove < 0) {
972 $this->error++;
973 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
974 } else {
975 $moline = new MoLine($this->db);
976 $moline->fetch($lineDetails['rowid']);
977
978 $resdel = $moline->delete($user, $notrigger);
979 if ($resdel < 0) {
980 $this->error++;
981 setEventMessages($moline->error, $moline->errors, 'errors');
982 }
983 }
984 }
985
986 if (empty($this->error)) {
987 $result = $this->deleteLineCommon($user, $idline, $notrigger);
988 }
989 } else {
990 // No child lines and no associated movement
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:37
__construct(DoliDB $db)
Constructor.
Definition mo.class.php:254
fetchLinesLinked($role, $lineid=0)
Get list of lines linked to current line for a defined role.
Definition mo.class.php:575
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:471
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:294
fetch($id, $ref=null)
Load object in memory from the database.
Definition mo.class.php:454
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the database.
Definition mo.class.php:491
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:815
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:662
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:696
deleteLine(User $user, $idline, $notrigger=0, $fk_movement=0)
Delete a line of object in database.
Definition mo.class.php:906
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:627
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition mo.class.php:352
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.