dolibarr  18.0.0-alpha
bom.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2019 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2023 Benjamin Falière <benjamin.faliere@altairis.fr>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
25 // Put here all includes required by your class file
26 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
27 require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
28 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
29 //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
30 //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
31 
32 
36 class BOM extends CommonObject
37 {
41  public $element = 'bom';
42 
46  public $table_element = 'bom_bom';
47 
51  public $ismultientitymanaged = 1;
52 
56  public $isextrafieldmanaged = 1;
57 
61  public $picto = 'bom';
62 
63 
64  const STATUS_DRAFT = 0;
65  const STATUS_VALIDATED = 1;
66  const STATUS_CANCELED = 9;
67 
68 
95  // BEGIN MODULEBUILDER PROPERTIES
99  public $fields = array(
100  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
101  'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=> 1, 'default'=>1, 'index'=>1, 'position'=>5),
102  'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'noteditable'=>1, 'visible'=>4, 'position'=>10, 'notnull'=>1, 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of BOM", 'showoncombobox'=>'1', 'csslist'=>'nowraponall'),
103  'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>30, 'notnull'=>1, 'searchall'=>1, 'showoncombobox'=>'2', 'autofocusoncreate'=>1, 'css'=>'minwidth300 maxwidth400', 'csslist'=>'tdoverflowmax200'),
104  'bomtype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>1, 'position'=>33, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing', 1=>'Disassemble'), 'css'=>'minwidth175', 'csslist'=>'minwidth175 center'),
105  //'bomtype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'position'=>32, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing')),
106  'fk_product' => array('type'=>'integer:Product:product/class/product.class.php:1:((finished:is:null) or (finished:!=:0))', 'label'=>'Product', 'picto'=>'product', 'enabled'=>1, 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'help'=>'ProductBOMHelp', 'css'=>'maxwidth500', 'csslist'=>'tdoverflowmax100'),
107  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
108  'qty' => array('type'=>'real', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'position'=>55, 'notnull'=>1, 'isameasure'=>'1', 'css'=>'maxwidth50imp right'),
109  //'efficiency' => array('type'=>'real', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>-1, 'default'=>1, 'position'=>100, 'notnull'=>0, 'css'=>'maxwidth50imp', 'help'=>'ValueOfMeansLossForProductProduced'),
110  'duration' => array('type'=>'duration', 'label'=>'EstimatedDuration', 'enabled'=>1, 'visible'=>-1, 'position'=>101, 'notnull'=>-1, 'css'=>'maxwidth50imp', 'help'=>'EstimatedDurationDesc'),
111  'fk_warehouse' => array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php:0', 'label'=>'WarehouseForProduction', 'picto'=>'stock', 'enabled'=>1, 'visible'=>-1, 'position'=>102, 'css'=>'maxwidth500', 'csslist'=>'tdoverflowmax100'),
112  'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>-2, 'position'=>161, 'notnull'=>-1,),
113  'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>-2, 'position'=>162, 'notnull'=>-1,),
114  'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>300, 'notnull'=>1,),
115  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,),
116  'date_valid' => array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>502, 'notnull'=>0,),
117  'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserCreation', 'picto'=>'user', 'enabled'=>1, 'visible'=>-2, 'position'=>510, 'notnull'=>1, 'foreignkey'=>'user.rowid', 'csslist'=>'tdoverflowmax100'),
118  'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'picto'=>'user', 'enabled'=>1, 'visible'=>-2, 'position'=>511, 'notnull'=>-1, 'csslist'=>'tdoverflowmax100'),
119  'fk_user_valid' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'picto'=>'user', 'enabled'=>1, 'visible'=>-2, 'position'=>512, 'notnull'=>0, 'csslist'=>'tdoverflowmax100'),
120  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
121  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
122  'status' => array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>2, 'position'=>1000, 'notnull'=>1, 'default'=>0, 'index'=>1, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Enabled', 9=>'Disabled')),
123  );
124 
128  public $rowid;
129 
133  public $ref;
134 
138  public $label;
139 
143  public $bomtype;
144 
148  public $description;
149 
153  public $date_creation;
154 
155 
156  public $tms;
157 
161  public $fk_user_creat;
162 
166  public $fk_user_modif;
167 
171  public $import_key;
172 
176  public $status;
177 
181  public $fk_product;
182  public $qty;
183  public $efficiency;
184  // END MODULEBUILDER PROPERTIES
185 
186 
187  // If this object has a subtable with lines
188 
192  public $table_element_line = 'bom_bomline';
193 
197  public $fk_element = 'fk_bom';
198 
202  public $class_element_line = 'BOMLine';
203 
204  // /**
205  // * @var array List of child tables. To test if we can delete object.
206  // */
207  // protected $childtables=array();
208 
212  protected $childtablesoncascade = array('bom_bomline');
213 
217  public $lines = array();
218 
222  public $total_cost = 0;
223 
227  public $unit_cost = 0;
228 
229 
230 
236  public function __construct(DoliDB $db)
237  {
238  global $conf, $langs;
239 
240  $this->db = $db;
241 
242  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
243  $this->fields['rowid']['visible'] = 0;
244  }
245  if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
246  $this->fields['entity']['enabled'] = 0;
247  }
248 
249  // Unset fields that are disabled
250  foreach ($this->fields as $key => $val) {
251  if (isset($val['enabled']) && empty($val['enabled'])) {
252  unset($this->fields[$key]);
253  }
254  }
255 
256  // Translate some data of arrayofkeyval
257  foreach ($this->fields as $key => $val) {
258  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
259  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
260  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
261  }
262  }
263  }
264  }
265 
273  public function create(User $user, $notrigger = false)
274  {
275  if ($this->efficiency <= 0 || $this->efficiency > 1) {
276  $this->efficiency = 1;
277  }
278 
279  return $this->createCommon($user, $notrigger);
280  }
281 
289  public function createFromClone(User $user, $fromid)
290  {
291  global $langs, $hookmanager, $extrafields;
292  $error = 0;
293 
294  dol_syslog(__METHOD__, LOG_DEBUG);
295 
296  $object = new self($this->db);
297 
298  $this->db->begin();
299 
300  // Load source object
301  $result = $object->fetchCommon($fromid);
302  if ($result > 0 && !empty($object->table_element_line)) {
303  $object->fetchLines();
304  }
305 
306  // Get lines so they will be clone
307  //foreach ($object->lines as $line)
308  // $line->fetch_optionals();
309 
310  // Reset some properties
311  unset($object->id);
312  unset($object->fk_user_creat);
313  unset($object->import_key);
314 
315  // Clear fields
316  $object->ref = empty($this->fields['ref']['default']) ? $langs->trans("copy_of_").$object->ref : $this->fields['ref']['default'];
317  $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
318  $object->status = self::STATUS_DRAFT;
319  // ...
320  // Clear extrafields that are unique
321  if (is_array($object->array_options) && count($object->array_options) > 0) {
322  $extrafields->fetch_name_optionals_label($object->table_element);
323  foreach ($object->array_options as $key => $option) {
324  $shortkey = preg_replace('/options_/', '', $key);
325  if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
326  //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
327  unset($object->array_options[$key]);
328  }
329  }
330  }
331 
332  // Create clone
333  $object->context['createfromclone'] = 'createfromclone';
334  $result = $object->createCommon($user);
335  if ($result < 0) {
336  $error++;
337  $this->error = $object->error;
338  $this->errors = $object->errors;
339  }
340 
341  if (!$error) {
342  // copy internal contacts
343  if ($this->copy_linked_contact($object, 'internal') < 0) {
344  $error++;
345  }
346  }
347 
348  if (!$error) {
349  // copy external contacts if same company
350  if (property_exists($this, 'socid') && $this->socid == $object->socid) {
351  if ($this->copy_linked_contact($object, 'external') < 0) {
352  $error++;
353  }
354  }
355  }
356 
357  // If there is lines, create lines too
358 
359 
360 
361  unset($object->context['createfromclone']);
362 
363  // End
364  if (!$error) {
365  $this->db->commit();
366  return $object;
367  } else {
368  $this->db->rollback();
369  return -1;
370  }
371  }
372 
380  public function fetch($id, $ref = null)
381  {
382  $result = $this->fetchCommon($id, $ref);
383 
384  if ($result > 0 && !empty($this->table_element_line)) {
385  $this->fetchLines();
386  }
387  //$this->calculateCosts(); // This consume a high number of subrequests. Do not call it into fetch but when you need it.
388 
389  return $result;
390  }
391 
397  public function fetchLines()
398  {
399  $this->lines = array();
400 
401  $result = $this->fetchLinesCommon();
402  return $result;
403  }
404 
412  public function fetchLinesbytypeproduct($typeproduct = 0)
413  {
414  $this->lines = array();
415 
416  $objectlineclassname = get_class($this).'Line';
417  if (!class_exists($objectlineclassname)) {
418  $this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon';
419  return -1;
420  }
421 
422  $objectline = new $objectlineclassname($this->db);
423 
424  $sql = "SELECT ".$objectline->getFieldList('l');
425  $sql .= " FROM ".$this->db->prefix().$objectline->table_element." as l";
426  $sql .= " LEFT JOIN ".$this->db->prefix()."product as p ON p.rowid = l.fk_product";
427  $sql .= " WHERE l.fk_".$this->db->escape($this->element)." = ".((int) $this->id);
428  $sql .= " AND p.fk_product_type = ". ((int) $typeproduct);
429  if (isset($objectline->fields['position'])) {
430  $sql .= $this->db->order('position', 'ASC');
431  }
432 
433  $resql = $this->db->query($sql);
434  if ($resql) {
435  $num_rows = $this->db->num_rows($resql);
436  $i = 0;
437  while ($i < $num_rows) {
438  $obj = $this->db->fetch_object($resql);
439  if ($obj) {
440  $newline = new $objectlineclassname($this->db);
441  $newline->setVarsFromFetchObj($obj);
442 
443  $this->lines[] = $newline;
444  }
445  $i++;
446  }
447 
448  return $num_rows;
449  } else {
450  $this->error = $this->db->lasterror();
451  $this->errors[] = $this->error;
452  return -1;
453  }
454  }
455 
456 
468  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
469  {
470  global $conf;
471 
472  dol_syslog(__METHOD__, LOG_DEBUG);
473 
474  $records = array();
475 
476  $sql = 'SELECT ';
477  $sql .= $this->getFieldList();
478  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
479  if ($this->ismultientitymanaged) {
480  $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
481  } else {
482  $sql .= ' WHERE 1 = 1';
483  }
484  // Manage filter
485  $sqlwhere = array();
486  if (count($filter) > 0) {
487  foreach ($filter as $key => $value) {
488  if ($key == 't.rowid') {
489  $sqlwhere[] = $key." = ".((int) $value);
490  } elseif (strpos($key, 'date') !== false) {
491  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
492  } elseif ($key == 'customsql') {
493  $sqlwhere[] = $value;
494  } else {
495  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
496  }
497  }
498  }
499  if (count($sqlwhere) > 0) {
500  $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
501  }
502 
503  if (!empty($sortfield)) {
504  $sql .= $this->db->order($sortfield, $sortorder);
505  }
506  if (!empty($limit)) {
507  $sql .= $this->db->plimit($limit, $offset);
508  }
509 
510  $resql = $this->db->query($sql);
511  if ($resql) {
512  $num = $this->db->num_rows($resql);
513 
514  while ($obj = $this->db->fetch_object($resql)) {
515  $record = new self($this->db);
516  $record->setVarsFromFetchObj($obj);
517 
518  $records[$record->id] = $record;
519  }
520  $this->db->free($resql);
521 
522  return $records;
523  } else {
524  $this->errors[] = 'Error '.$this->db->lasterror();
525  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
526 
527  return -1;
528  }
529  }
530 
538  public function update(User $user, $notrigger = false)
539  {
540  if ($this->efficiency <= 0 || $this->efficiency > 1) {
541  $this->efficiency = 1;
542  }
543 
544  return $this->updateCommon($user, $notrigger);
545  }
546 
554  public function delete(User $user, $notrigger = false)
555  {
556  return $this->deleteCommon($user, $notrigger);
557  //return $this->deleteCommon($user, $notrigger, 1);
558  }
559 
575  public function addLine($fk_product, $qty, $qty_frozen = 0, $disable_stock_change = 0, $efficiency = 1.0, $position = -1, $fk_bom_child = null, $import_key = null, $fk_unit = '', $array_options = 0)
576  {
577  global $mysoc, $conf, $langs, $user;
578 
579  $logtext = "::addLine bomid=$this->id, qty=$qty, fk_product=$fk_product, qty_frozen=$qty_frozen, disable_stock_change=$disable_stock_change, efficiency=$efficiency";
580  $logtext .= ", fk_bom_child=$fk_bom_child, import_key=$import_key";
581  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
582 
583  if ($this->statut == self::STATUS_DRAFT) {
584  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
585 
586  // Clean parameters
587  if (empty($qty)) {
588  $qty = 0;
589  }
590  if (empty($qty_frozen)) {
591  $qty_frozen = 0;
592  }
593  if (empty($disable_stock_change)) {
594  $disable_stock_change = 0;
595  }
596  if (empty($efficiency)) {
597  $efficiency = 1.0;
598  }
599  if (empty($fk_bom_child)) {
600  $fk_bom_child = null;
601  }
602  if (empty($import_key)) {
603  $import_key = null;
604  }
605  if (empty($position)) {
606  $position = -1;
607  }
608 
609  $qty = price2num($qty);
610  $efficiency = price2num($efficiency);
611  $position = price2num($position);
612 
613  $this->db->begin();
614 
615  // Rank to use
616  $rangMax = $this->line_max();
617  $rankToUse = $position;
618  if ($rankToUse <= 0 or $rankToUse > $rangMax) { // New line after existing lines
619  $rankToUse = $rangMax + 1;
620  } else { // New line between the existing lines
621  foreach ($this->lines as $bl) {
622  if ($bl->position >= $rankToUse) {
623  $bl->position++;
624  $bl->update($user);
625  }
626  }
627  }
628 
629  // Insert line
630  $this->line = new BOMLine($this->db);
631 
632  $this->line->context = $this->context;
633 
634  $this->line->fk_bom = $this->id;
635  $this->line->fk_product = $fk_product;
636  $this->line->qty = $qty;
637  $this->line->qty_frozen = $qty_frozen;
638  $this->line->disable_stock_change = $disable_stock_change;
639  $this->line->efficiency = $efficiency;
640  $this->line->fk_bom_child = $fk_bom_child;
641  $this->line->import_key = $import_key;
642  $this->line->position = $rankToUse;
643  $this->line->fk_unit = $fk_unit;
644 
645  if (is_array($array_options) && count($array_options) > 0) {
646  $this->line->array_options = $array_options;
647  }
648 
649  $result = $this->line->create($user);
650 
651  if ($result > 0) {
652  $this->calculateCosts();
653  $this->db->commit();
654  return $result;
655  } else {
656  $this->error = $this->line->error;
657  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
658  $this->db->rollback();
659  return -2;
660  }
661  } else {
662  dol_syslog(get_class($this)."::addLine status of BOM must be Draft to allow use of ->addLine()", LOG_ERR);
663  return -3;
664  }
665  }
666 
681  public function updateLine($rowid, $qty, $qty_frozen = 0, $disable_stock_change = 0, $efficiency = 1.0, $position = -1, $import_key = null, $fk_unit = 0, $array_options = 0)
682  {
683  global $mysoc, $conf, $langs, $user;
684 
685  $logtext = "::updateLine bomid=$this->id, qty=$qty, qty_frozen=$qty_frozen, disable_stock_change=$disable_stock_change, efficiency=$efficiency";
686  $logtext .= ", import_key=$import_key";
687  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
688 
689  if ($this->statut == self::STATUS_DRAFT) {
690  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
691 
692  // Clean parameters
693  if (empty($qty)) {
694  $qty = 0;
695  }
696  if (empty($qty_frozen)) {
697  $qty_frozen = 0;
698  }
699  if (empty($disable_stock_change)) {
700  $disable_stock_change = 0;
701  }
702  if (empty($efficiency)) {
703  $efficiency = 1.0;
704  }
705  if (empty($import_key)) {
706  $import_key = null;
707  }
708  if (empty($position)) {
709  $position = -1;
710  }
711 
712  $qty = price2num($qty);
713  $efficiency = price2num($efficiency);
714  $position = price2num($position);
715 
716  $this->db->begin();
717 
718  //Fetch current line from the database and then clone the object and set it in $oldline property
719  $line = new BOMLine($this->db);
720  $line->fetch($rowid);
721  $line->fetch_optionals();
722 
723  $staticLine = clone $line;
724  $line->oldcopy = $staticLine;
725  $this->line = $line;
726  $this->line->context = $this->context;
727 
728  // Rank to use
729  $rankToUse = (int) $position;
730  if ($rankToUse != $line->oldcopy->position) { // check if position have a new value
731  foreach ($this->lines as $bl) {
732  if ($bl->position >= $rankToUse AND $bl->position < ($line->oldcopy->position + 1)) { // move rank up
733  $bl->position++;
734  $bl->update($user);
735  }
736  if ($bl->position <= $rankToUse AND $bl->position > ($line->oldcopy->position)) { // move rank down
737  $bl->position--;
738  $bl->update($user);
739  }
740  }
741  }
742 
743 
744  $this->line->fk_bom = $this->id;
745  $this->line->qty = $qty;
746  $this->line->qty_frozen = $qty_frozen;
747  $this->line->disable_stock_change = $disable_stock_change;
748  $this->line->efficiency = $efficiency;
749  $this->line->import_key = $import_key;
750  $this->line->position = $rankToUse;
751  if (!empty($fk_unit)) {
752  $this->line->fk_unit = $fk_unit;
753  }
754 
755  if (is_array($array_options) && count($array_options) > 0) {
756  // We replace values in this->line->array_options only for entries defined into $array_options
757  foreach ($array_options as $key => $value) {
758  $this->line->array_options[$key] = $array_options[$key];
759  }
760  }
761 
762  $result = $this->line->update($user);
763 
764  if ($result > 0) {
765  $this->calculateCosts();
766  $this->db->commit();
767  return $result;
768  } else {
769  $this->error = $this->line->error;
770  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
771  $this->db->rollback();
772  return -2;
773  }
774  } else {
775  dol_syslog(get_class($this)."::addLine status of BOM must be Draft to allow use of ->addLine()", LOG_ERR);
776  return -3;
777  }
778  }
779 
788  public function deleteLine(User $user, $idline, $notrigger = false)
789  {
790  if ($this->status < 0) {
791  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
792  return -2;
793  }
794 
795  $this->db->begin();
796 
797  //Fetch current line from the database and then clone the object and set it in $oldline property
798  $line = new BOMLine($this->db);
799  $line->fetch($idline);
800  $line->fetch_optionals();
801 
802  $staticLine = clone $line;
803  $line->oldcopy = $staticLine;
804  $this->line = $line;
805  $this->line->context = $this->context;
806 
807  $result = $this->line->delete($user, $notrigger);
808 
809  //Positions (rank) reordering
810  foreach ($this->lines as $bl) {
811  if ($bl->position > ($line->oldcopy->position)) { // move rank down
812  $bl->position--;
813  $bl->update($user);
814  }
815  }
816 
817  if ($result > 0) {
818  $this->calculateCosts();
819  $this->db->commit();
820  return $result;
821  } else {
822  $this->error = $this->line->error;
823  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
824  $this->db->rollback();
825  return -2;
826  }
827  }
828 
836  public function getNextNumRef($prod)
837  {
838  global $langs, $conf;
839  $langs->load("mrp");
840 
841  if (!empty($conf->global->BOM_ADDON)) {
842  $mybool = false;
843 
844  $file = $conf->global->BOM_ADDON.".php";
845  $classname = $conf->global->BOM_ADDON;
846 
847  // Include file with class
848  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
849  foreach ($dirmodels as $reldir) {
850  $dir = dol_buildpath($reldir."core/modules/bom/");
851 
852  // Load file with numbering class (if found)
853  $mybool |= @include_once $dir.$file;
854  }
855 
856  if ($mybool === false) {
857  dol_print_error('', "Failed to include file ".$file);
858  return '';
859  }
860 
861  $obj = new $classname();
862  $numref = $obj->getNextValue($prod, $this);
863 
864  if ($numref != "") {
865  return $numref;
866  } else {
867  $this->error = $obj->error;
868  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
869  return "";
870  }
871  } else {
872  print $langs->trans("Error")." ".$langs->trans("Error_BOM_ADDON_NotDefined");
873  return "";
874  }
875  }
876 
884  public function validate($user, $notrigger = 0)
885  {
886  global $conf, $langs;
887 
888  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
889 
890  $error = 0;
891 
892  // Protection
893  if ($this->status == self::STATUS_VALIDATED) {
894  dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
895  return 0;
896  }
897 
898  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->create))
899  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
900  {
901  $this->error='NotEnoughPermissions';
902  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
903  return -1;
904  }*/
905 
906  $now = dol_now();
907 
908  $this->db->begin();
909 
910  // Define new ref
911  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
912  $this->fetch_product();
913  $num = $this->getNextNumRef($this->product);
914  } else {
915  $num = $this->ref;
916  }
917  $this->newref = dol_sanitizeFileName($num);
918 
919  // Validate
920  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
921  $sql .= " SET ref = '".$this->db->escape($num)."',";
922  $sql .= " status = ".self::STATUS_VALIDATED.",";
923  $sql .= " date_valid='".$this->db->idate($now)."',";
924  $sql .= " fk_user_valid = ".((int) $user->id);
925  $sql .= " WHERE rowid = ".((int) $this->id);
926 
927  dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
928  $resql = $this->db->query($sql);
929  if (!$resql) {
930  dol_print_error($this->db);
931  $this->error = $this->db->lasterror();
932  $error++;
933  }
934 
935  if (!$error && !$notrigger) {
936  // Call trigger
937  $result = $this->call_trigger('BOM_VALIDATE', $user);
938  if ($result < 0) {
939  $error++;
940  }
941  // End call triggers
942  }
943 
944  if (!$error) {
945  $this->oldref = $this->ref;
946 
947  // Rename directory if dir was a temporary ref
948  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
949  // Now we rename also files into index
950  $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'bom/".$this->db->escape($this->newref)."'";
951  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'bom/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
952  $resql = $this->db->query($sql);
953  if (!$resql) {
954  $error++; $this->error = $this->db->lasterror();
955  }
956 
957  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
958  $oldref = dol_sanitizeFileName($this->ref);
959  $newref = dol_sanitizeFileName($num);
960  $dirsource = $conf->bom->dir_output.'/'.$oldref;
961  $dirdest = $conf->bom->dir_output.'/'.$newref;
962  if (!$error && file_exists($dirsource)) {
963  dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
964 
965  if (@rename($dirsource, $dirdest)) {
966  dol_syslog("Rename ok");
967  // Rename docs starting with $oldref with $newref
968  $listoffiles = dol_dir_list($conf->bom->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
969  foreach ($listoffiles as $fileentry) {
970  $dirsource = $fileentry['name'];
971  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
972  $dirsource = $fileentry['path'].'/'.$dirsource;
973  $dirdest = $fileentry['path'].'/'.$dirdest;
974  @rename($dirsource, $dirdest);
975  }
976  }
977  }
978  }
979  }
980 
981  // Set new ref and current status
982  if (!$error) {
983  $this->ref = $num;
984  $this->status = self::STATUS_VALIDATED;
985  }
986 
987  if (!$error) {
988  $this->db->commit();
989  return 1;
990  } else {
991  $this->db->rollback();
992  return -1;
993  }
994  }
995 
1003  public function setDraft($user, $notrigger = 0)
1004  {
1005  // Protection
1006  if ($this->status <= self::STATUS_DRAFT) {
1007  return 0;
1008  }
1009 
1010  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1011  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1012  {
1013  $this->error='Permission denied';
1014  return -1;
1015  }*/
1016 
1017  return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'BOM_UNVALIDATE');
1018  }
1019 
1027  public function cancel($user, $notrigger = 0)
1028  {
1029  // Protection
1030  if ($this->status != self::STATUS_VALIDATED) {
1031  return 0;
1032  }
1033 
1034  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1035  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1036  {
1037  $this->error='Permission denied';
1038  return -1;
1039  }*/
1040 
1041  return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'BOM_CLOSE');
1042  }
1043 
1051  public function reopen($user, $notrigger = 0)
1052  {
1053  // Protection
1054  if ($this->status != self::STATUS_CANCELED) {
1055  return 0;
1056  }
1057 
1058  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1059  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1060  {
1061  $this->error='Permission denied';
1062  return -1;
1063  }*/
1064 
1065  return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'BOM_REOPEN');
1066  }
1067 
1074  public function getTooltipContentArray($params)
1075  {
1076  global $conf, $langs, $user;
1077 
1078  $langs->loadLangs(['product', 'mrp']);
1079 
1080  $datas = [];
1081 
1082  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1083  return ['optimize' => $langs->trans("ShowBillOfMaterials")];
1084  }
1085  $picto = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("BillOfMaterials").'</u>';
1086  if (isset($this->status)) {
1087  $picto .= ' '.$this->getLibStatut(5);
1088  }
1089  $datas['picto'] = $picto;
1090  $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1091  if (isset($this->label)) {
1092  $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1093  }
1094  if (!empty($this->fk_product) && $this->fk_product > 0) {
1095  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1096  $product = new Product($this->db);
1097  $resultFetch = $product->fetch($this->fk_product);
1098  if ($resultFetch > 0) {
1099  $datas['product'] = "<br><b>".$langs->trans("Product").'</b>: '.$product->ref.' - '.$product->label;
1100  }
1101  }
1102 
1103  return $datas;
1104  }
1105 
1116  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1117  {
1118  global $db, $conf, $langs, $hookmanager;
1119 
1120  if (!empty($conf->dol_no_mouse_hover)) {
1121  $notooltip = 1; // Force disable tooltips
1122  }
1123 
1124  $result = '';
1125  $params = [
1126  'id' => $this->id,
1127  'objecttype' => $this->element,
1128  'option' => $option,
1129  ];
1130  $classfortooltip = 'classfortooltip';
1131  $dataparams = '';
1132  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1133  $classfortooltip = 'classforajaxtooltip';
1134  $dataparams = ' data-params='.json_encode($params);
1135  // $label = $langs->trans('Loading');
1136  }
1137 
1138  $label = implode($this->getTooltipContentArray($params));
1139 
1140 
1141  $url = DOL_URL_ROOT.'/bom/bom_card.php?id='.$this->id;
1142 
1143  if ($option != 'nolink') {
1144  // Add param to save lastsearch_values or not
1145  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1146  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1147  $add_save_lastsearch_values = 1;
1148  }
1149  if ($add_save_lastsearch_values) {
1150  $url .= '&save_lastsearch_values=1';
1151  }
1152  }
1153 
1154  $linkclose = '';
1155  if (empty($notooltip)) {
1156  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1157  $label = $langs->trans("ShowBillOfMaterials");
1158  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1159  }
1160  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1161  $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1162  } else {
1163  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1164  }
1165 
1166  $linkstart = '<a href="'.$url.'"';
1167  $linkstart .= $linkclose.'>';
1168  $linkend = '</a>';
1169 
1170  $result .= $linkstart;
1171  if ($withpicto) {
1172  $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : $dataparams.' class="'.(($withpicto != 2) ? 'paddingright ' : '').$classfortooltip.'"'), 0, 0, $notooltip ? 0 : 1);
1173  }
1174  if ($withpicto != 2) {
1175  $result .= $this->ref;
1176  }
1177  $result .= $linkend;
1178  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1179 
1180  global $action, $hookmanager;
1181  $hookmanager->initHooks(array('bomdao'));
1182  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1183  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1184  if ($reshook > 0) {
1185  $result = $hookmanager->resPrint;
1186  } else {
1187  $result .= $hookmanager->resPrint;
1188  }
1189 
1190  return $result;
1191  }
1192 
1199  public function getLibStatut($mode = 0)
1200  {
1201  return $this->LibStatut($this->status, $mode);
1202  }
1203 
1204  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1212  public function LibStatut($status, $mode = 0)
1213  {
1214  // phpcs:enable
1215  if (empty($this->labelStatus)) {
1216  global $langs;
1217  //$langs->load("mrp");
1218  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1219  $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
1220  $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
1221  }
1222 
1223  $statusType = 'status'.$status;
1224  if ($status == self::STATUS_VALIDATED) {
1225  $statusType = 'status4';
1226  }
1227  if ($status == self::STATUS_CANCELED) {
1228  $statusType = 'status6';
1229  }
1230 
1231  return dolGetStatus($this->labelStatus[$status], $this->labelStatus[$status], '', $statusType, $mode);
1232  }
1233 
1240  public function info($id)
1241  {
1242  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1243  $sql .= ' fk_user_creat, fk_user_modif';
1244  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1245  $sql .= ' WHERE t.rowid = '.((int) $id);
1246  $result = $this->db->query($sql);
1247  if ($result) {
1248  if ($this->db->num_rows($result)) {
1249  $obj = $this->db->fetch_object($result);
1250  $this->id = $obj->rowid;
1251 
1252  $this->user_creation_id = $obj->fk_user_creat;
1253  $this->user_modification_id = $obj->fk_user_modif;
1254  $this->date_creation = $this->db->jdate($obj->datec);
1255  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1256  }
1257 
1258  $this->db->free($result);
1259  } else {
1260  dol_print_error($this->db);
1261  }
1262  }
1263 
1269  public function getLinesArray()
1270  {
1271  $this->lines = array();
1272 
1273  $objectline = new BOMLine($this->db);
1274  $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_bom = '.((int) $this->id)));
1275 
1276  if (is_numeric($result)) {
1277  $this->error = $objectline->error;
1278  $this->errors = $objectline->errors;
1279  return $result;
1280  } else {
1281  $this->lines = $result;
1282  return $this->lines;
1283  }
1284  }
1285 
1297  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1298  {
1299  global $conf, $langs;
1300 
1301  $langs->load("mrp");
1302  $outputlangs->load("products");
1303 
1304  if (!dol_strlen($modele)) {
1305  $modele = 'standard';
1306 
1307  if ($this->model_pdf) {
1308  $modele = $this->model_pdf;
1309  } elseif (!empty($conf->global->BOM_ADDON_PDF)) {
1310  $modele = $conf->global->BOM_ADDON_PDF;
1311  }
1312  }
1313 
1314  $modelpath = "core/modules/bom/doc/";
1315 
1316  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1317  }
1318 
1325  public function initAsSpecimen()
1326  {
1327  $this->initAsSpecimenCommon();
1328  $this->ref = 'BOM-123';
1329  $this->date = $this->date_creation;
1330  }
1331 
1332 
1339  public function doScheduledJob()
1340  {
1341  global $conf, $langs;
1342 
1343  //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1344 
1345  $error = 0;
1346  $this->output = '';
1347  $this->error = '';
1348 
1349  dol_syslog(__METHOD__, LOG_DEBUG);
1350 
1351  $now = dol_now();
1352 
1353  $this->db->begin();
1354 
1355  // ...
1356 
1357  $this->db->commit();
1358 
1359  return $error;
1360  }
1361 
1368  public function calculateCosts()
1369  {
1370  global $conf, $hookmanager;
1371 
1372  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1373  $this->unit_cost = 0;
1374  $this->total_cost = 0;
1375 
1376  $parameters=array();
1377  $reshook = $hookmanager->executeHooks('calculateCostsBom', $parameters, $this); // Note that $action and $object may have been modified by hook
1378 
1379  if ($reshook > 0) {
1380  return $hookmanager->resPrint;
1381  }
1382 
1383  if (is_array($this->lines) && count($this->lines)) {
1384  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1385  $productFournisseur = new ProductFournisseur($this->db);
1386  $tmpproduct = new Product($this->db);
1387 
1388  foreach ($this->lines as &$line) {
1389  $tmpproduct->cost_price = 0;
1390  $tmpproduct->pmp = 0;
1391  $result = $tmpproduct->fetch($line->fk_product, '', '', '', 0, 1, 1); // We discard selling price and language loading
1392 
1393  if ($tmpproduct->type == $tmpproduct::TYPE_PRODUCT) {
1394  if (empty($line->fk_bom_child)) {
1395  if ($result < 0) {
1396  $this->error = $tmpproduct->error;
1397  return -1;
1398  }
1399  $line->unit_cost = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
1400  if (empty($line->unit_cost)) {
1401  if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0) {
1402  if ($productFournisseur->fourn_remise_percent != "0") {
1403  $line->unit_cost = $productFournisseur->fourn_unitprice_with_discount;
1404  } else {
1405  $line->unit_cost = $productFournisseur->fourn_unitprice;
1406  }
1407  }
1408  }
1409 
1410  $line->total_cost = price2num($line->qty * $line->unit_cost, 'MT');
1411 
1412  $this->total_cost += $line->total_cost;
1413  } else {
1414  $bom_child = new BOM($this->db);
1415  $res = $bom_child->fetch($line->fk_bom_child);
1416  if ($res > 0) {
1417  $bom_child->calculateCosts();
1418  $line->childBom[] = $bom_child;
1419  $this->total_cost += price2num($bom_child->total_cost * $line->qty, 'MT');
1420  $this->total_cost += $line->total_cost;
1421  } else {
1422  $this->error = $bom_child->error;
1423  return -2;
1424  }
1425  }
1426  } else {
1427  //Convert qty to hour
1428  $unit = measuringUnitString($line->fk_unit, '', '', 1);
1429  $qty = convertDurationtoHour($line->qty, $unit);
1430 
1431  if (isModEnabled('workstation') && !empty($tmpproduct->fk_default_workstation)) {
1432  $workstation = new Workstation($this->db);
1433  $res = $workstation->fetch($tmpproduct->fk_default_workstation);
1434 
1435  if ($res > 0) $line->total_cost = price2num($qty * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated), 'MT');
1436  else {
1437  $this->error = $workstation->error;
1438  return -3;
1439  }
1440  } else {
1441  $line->total_cost = price2num($qty * $tmpproduct->cost_price, 'MT');
1442  }
1443 
1444  $this->total_cost += $line->total_cost;
1445  }
1446  }
1447 
1448  $this->total_cost = price2num($this->total_cost, 'MT');
1449 
1450  if ($this->qty > 0) {
1451  $this->unit_cost = price2num($this->total_cost / $this->qty, 'MU');
1452  } elseif ($this->qty < 0) {
1453  $this->unit_cost = price2num($this->total_cost * $this->qty, 'MU');
1454  }
1455  }
1456 
1457  return 1;
1458  }
1459 
1468  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1469  {
1470  $tables = array(
1471  'bom_bomline'
1472  );
1473 
1474  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1475  }
1476 
1484  public function getNetNeeds(&$TNetNeeds = array(), $qty = 0)
1485  {
1486  if (!empty($this->lines)) {
1487  foreach ($this->lines as $line) {
1488  if (!empty($line->childBom)) {
1489  foreach ($line->childBom as $childBom) $childBom->getNetNeeds($TNetNeeds, $line->qty*$qty);
1490  } else {
1491  if (empty($TNetNeeds[$line->fk_product])) {
1492  $TNetNeeds[$line->fk_product] = 0;
1493  }
1494  $TNetNeeds[$line->fk_product] += $line->qty*$qty;
1495  }
1496  }
1497  }
1498  }
1499 
1508  public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0)
1509  {
1510  if (!empty($this->lines)) {
1511  foreach ($this->lines as $line) {
1512  if (!empty($line->childBom)) {
1513  foreach ($line->childBom as $childBom) {
1514  $TNetNeeds[$childBom->id]['bom'] = $childBom;
1515  $TNetNeeds[$childBom->id]['parentid'] = $this->id;
1516  $TNetNeeds[$childBom->id]['qty'] = $line->qty*$qty;
1517  $TNetNeeds[$childBom->id]['level'] = $level;
1518  $childBom->getNetNeedsTree($TNetNeeds, $line->qty*$qty, $level+1);
1519  }
1520  } else {
1521  $TNetNeeds[$this->id]['product'][$line->fk_product]['qty'] += $line->qty * $qty;
1522  $TNetNeeds[$this->id]['product'][$line->fk_product]['level'] = $level;
1523  }
1524  }
1525  }
1526  }
1527 
1536  public function getParentBomTreeRecursive(&$TParentBom, $bom_id = '', $level = 1)
1537  {
1538 
1539  // Protection against infinite loop
1540  if ($level > 1000) {
1541  return;
1542  }
1543 
1544  if (empty($bom_id)) $bom_id=$this->id;
1545 
1546  $sql = 'SELECT l.fk_bom, b.label
1547  FROM '.MAIN_DB_PREFIX.'bom_bomline l
1548  INNER JOIN '.MAIN_DB_PREFIX.$this->table_element.' b ON b.rowid = l.fk_bom
1549  WHERE fk_bom_child = '.((int) $bom_id);
1550 
1551  $resql = $this->db->query($sql);
1552  if (!empty($resql)) {
1553  while ($res = $this->db->fetch_object($resql)) {
1554  $TParentBom[$res->fk_bom] = $res->fk_bom;
1555  $this->getParentBomTreeRecursive($TParentBom, $res->fk_bom, $level+1);
1556  }
1557  }
1558  }
1559 
1567  public function getKanbanView($option = '', $arraydata = null)
1568  {
1569  global $db,$langs;
1570  $prod = new Product($db);
1571  $prod->fetch($this->fk_product);
1572 
1573  $return = '<div class="box-flex-item box-flex-grow-zero">';
1574  $return .= '<div class="info-box info-box-sm">';
1575  $return .= '<span class="info-box-icon bg-infobox-action">';
1576  $return .= img_picto('', $this->picto);
1577  $return .= '</span>';
1578  $return .= '<div class="info-box-content">';
1579  $return .= '<span class="info-box-ref">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : '').'</span>';
1580  if (property_exists($this, 'fields') && !empty($this->fields['bomtype']['arrayofkeyval'])) {
1581  $return .= '<br><span class="info-box-label opacitymedium">'.$langs->trans("Type").' : </span>';
1582  if ($this->bomtype == 0) {
1583  $return .= '<span class="info-box-label">'.$this->fields['bomtype']['arrayofkeyval'][0].'</span>';
1584  } else {
1585  $return .= '<span class="info-box-label">'.$this->fields['bomtype']['arrayofkeyval'][1].'</span>';
1586  }
1587  }
1588  if (property_exists($this, 'fk_product') && !is_null($this->fk_product)) {
1589  $return .= '<br><span class="info-box-label">'.$prod->getNomUrl(1).'</span>';
1590  }
1591  if (method_exists($this, 'getLibStatut')) {
1592  $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(5).'</div>';
1593  }
1594 
1595  $return .= '</div>';
1596  $return .= '</div>';
1597  $return .= '</div>';
1598  return $return;
1599  }
1600 }
1601 
1602 
1607 {
1611  public $element = 'bomline';
1612 
1616  public $table_element = 'bom_bomline';
1617 
1621  public $ismultientitymanaged = 0;
1622 
1626  public $isextrafieldmanaged = 1;
1627 
1631  public $picto = 'bomline';
1632 
1633 
1653  // BEGIN MODULEBUILDER PROPERTIES
1657  public $fields = array(
1658  'rowid' => array('type'=>'integer', 'label'=>'LineID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
1659  'fk_bom' => array('type'=>'integer:BillOfMaterials:societe/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1,),
1660  'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
1661  'fk_bom_child' => array('type'=>'integer:BOM:bom/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>-1, 'position'=>40, 'notnull'=>-1,),
1662  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
1663  'qty' => array('type'=>'double(24,8)', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'position'=>100, 'notnull'=>1, 'isameasure'=>'1',),
1664  'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
1665  'disable_stock_change' => array('type'=>'smallint', 'label'=>'DisableStockChange', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>108, 'css'=>'maxwidth50imp', 'help'=>'DisableStockChangeHelp'),
1666  'efficiency' => array('type'=>'double(24,8)', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'position'=>110, 'notnull'=>1, 'css'=>'maxwidth50imp', 'help'=>'ValueOfEfficiencyConsumedMeans'),
1667  'fk_unit' => array('type'=>'integer', 'label'=>'Unit', 'enabled'=>1, 'visible'=>1, 'position'=>120, 'notnull'=>-1,),
1668  'position' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>1, 'visible'=>0, 'default'=>0, 'position'=>200, 'notnull'=>1,),
1669  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
1670  );
1671 
1675  public $rowid;
1676 
1680  public $fk_bom;
1681 
1685  public $fk_product;
1686 
1690  public $fk_bom_child;
1691 
1695  public $description;
1696  public $qty;
1697 
1701  public $qty_frozen;
1702  public $disable_stock_change;
1703  public $efficiency;
1704 
1708  public $position;
1709 
1713  public $import_key;
1714  // END MODULEBUILDER PROPERTIES
1715 
1719  public $total_cost = 0;
1720 
1724  public $unit_cost = 0;
1725 
1726 
1730  public $childBom = array();
1731 
1732 
1738  public function __construct(DoliDB $db)
1739  {
1740  global $conf, $langs;
1741 
1742  $this->db = $db;
1743 
1744  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
1745  $this->fields['rowid']['visible'] = 0;
1746  }
1747  if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
1748  $this->fields['entity']['enabled'] = 0;
1749  }
1750 
1751  // Unset fields that are disabled
1752  foreach ($this->fields as $key => $val) {
1753  if (isset($val['enabled']) && empty($val['enabled'])) {
1754  unset($this->fields[$key]);
1755  }
1756  }
1757 
1758  // Translate some data of arrayofkeyval
1759  foreach ($this->fields as $key => $val) {
1760  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
1761  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
1762  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
1763  }
1764  }
1765  }
1766  }
1767 
1775  public function create(User $user, $notrigger = false)
1776  {
1777  if ($this->efficiency < 0 || $this->efficiency > 1) {
1778  $this->efficiency = 1;
1779  }
1780 
1781  return $this->createCommon($user, $notrigger);
1782  }
1783 
1791  public function fetch($id, $ref = null)
1792  {
1793  $result = $this->fetchCommon($id, $ref);
1794  //if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
1795  return $result;
1796  }
1797 
1809  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
1810  {
1811  global $conf;
1812 
1813  dol_syslog(__METHOD__, LOG_DEBUG);
1814 
1815  $records = array();
1816 
1817  $sql = 'SELECT ';
1818  $sql .= $this->getFieldList();
1819  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1820  if ($this->ismultientitymanaged) {
1821  $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
1822  } else {
1823  $sql .= ' WHERE 1 = 1';
1824  }
1825  // Manage filter
1826  $sqlwhere = array();
1827  if (count($filter) > 0) {
1828  foreach ($filter as $key => $value) {
1829  if ($key == 't.rowid') {
1830  $sqlwhere[] = $key." = ".((int) $value);
1831  } elseif (strpos($key, 'date') !== false) {
1832  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
1833  } elseif ($key == 'customsql') {
1834  $sqlwhere[] = $value;
1835  } else {
1836  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
1837  }
1838  }
1839  }
1840  if (count($sqlwhere) > 0) {
1841  $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
1842  }
1843 
1844  if (!empty($sortfield)) {
1845  $sql .= $this->db->order($sortfield, $sortorder);
1846  }
1847  if (!empty($limit)) {
1848  $sql .= $this->db->plimit($limit, $offset);
1849  }
1850 
1851  $resql = $this->db->query($sql);
1852  if ($resql) {
1853  $num = $this->db->num_rows($resql);
1854 
1855  while ($obj = $this->db->fetch_object($resql)) {
1856  $record = new self($this->db);
1857  $record->setVarsFromFetchObj($obj);
1858 
1859  $records[$record->id] = $record;
1860  }
1861  $this->db->free($resql);
1862 
1863  return $records;
1864  } else {
1865  $this->errors[] = 'Error '.$this->db->lasterror();
1866  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1867 
1868  return -1;
1869  }
1870  }
1871 
1879  public function update(User $user, $notrigger = false)
1880  {
1881  if ($this->efficiency < 0 || $this->efficiency > 1) {
1882  $this->efficiency = 1;
1883  }
1884 
1885  return $this->updateCommon($user, $notrigger);
1886  }
1887 
1895  public function delete(User $user, $notrigger = false)
1896  {
1897  return $this->deleteCommon($user, $notrigger);
1898  //return $this->deleteCommon($user, $notrigger, 1);
1899  }
1900 
1911  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1912  {
1913  global $db, $conf, $langs, $hookmanager;
1914 
1915  if (!empty($conf->dol_no_mouse_hover)) {
1916  $notooltip = 1; // Force disable tooltips
1917  }
1918 
1919  $result = '';
1920 
1921  $label = '<u>'.$langs->trans("BillOfMaterialsLine").'</u>';
1922  $label .= '<br>';
1923  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1924 
1925  $url = DOL_URL_ROOT.'/bom/bomline_card.php?id='.$this->id;
1926 
1927  if ($option != 'nolink') {
1928  // Add param to save lastsearch_values or not
1929  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1930  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1931  $add_save_lastsearch_values = 1;
1932  }
1933  if ($add_save_lastsearch_values) {
1934  $url .= '&save_lastsearch_values=1';
1935  }
1936  }
1937 
1938  $linkclose = '';
1939  if (empty($notooltip)) {
1940  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1941  $label = $langs->trans("ShowBillOfMaterialsLine");
1942  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1943  }
1944  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1945  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1946  } else {
1947  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1948  }
1949 
1950  $linkstart = '<a href="'.$url.'"';
1951  $linkstart .= $linkclose.'>';
1952  $linkend = '</a>';
1953 
1954  $result .= $linkstart;
1955  if ($withpicto) {
1956  $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1957  }
1958  if ($withpicto != 2) {
1959  $result .= $this->ref;
1960  }
1961  $result .= $linkend;
1962  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1963 
1964  global $action, $hookmanager;
1965  $hookmanager->initHooks(array('bomlinedao'));
1966  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1967  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1968  if ($reshook > 0) {
1969  $result = $hookmanager->resPrint;
1970  } else {
1971  $result .= $hookmanager->resPrint;
1972  }
1973 
1974  return $result;
1975  }
1976 
1983  public function getLibStatut($mode = 0)
1984  {
1985  return $this->LibStatut($this->status, $mode);
1986  }
1987 
1988  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1996  public function LibStatut($status, $mode = 0)
1997  {
1998  // phpcs:enable
1999  return '';
2000  }
2001 
2008  public function info($id)
2009  {
2010  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
2011  $sql .= ' fk_user_creat, fk_user_modif';
2012  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
2013  $sql .= ' WHERE t.rowid = '.((int) $id);
2014  $result = $this->db->query($sql);
2015  if ($result) {
2016  if ($this->db->num_rows($result)) {
2017  $obj = $this->db->fetch_object($result);
2018  $this->id = $obj->rowid;
2019  $this->user_creation_id = $obj->fk_user_creat;
2020  $this->user_modification_id = $obj->fk_user_modif;
2021  $this->date_creation = $this->db->jdate($obj->datec);
2022  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
2023  }
2024  $this->db->free($result);
2025  } else {
2026  dol_print_error($this->db);
2027  }
2028  }
2029 
2036  public function initAsSpecimen()
2037  {
2038  $this->initAsSpecimenCommon();
2039  }
2040 }
CommonObject\deleteCommon
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
Definition: commonobject.class.php:9643
CommonObject\setStatusCommon
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
Definition: commonobject.class.php:9921
db
$conf db
API class for accounts.
Definition: inc.php:41
CommonObject\fetchCommon
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9433
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1236
BOM\updateLine
updateLine($rowid, $qty, $qty_frozen=0, $disable_stock_change=0, $efficiency=1.0, $position=-1, $import_key=null, $fk_unit=0, $array_options=0)
Update an BOM line into database.
Definition: bom.class.php:681
CommonObject\copy_linked_contact
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
Definition: commonobject.class.php:1271
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
BOMLine\fetchAll
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
Definition: bom.class.php:1809
ProductFournisseur
Class to manage predefined suppliers products.
Definition: fournisseur.product.class.php:40
Workstation
Class for Workstation.
Definition: workstation.class.php:33
$sql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:745
convertDurationtoHour
convertDurationtoHour($duration_value, $duration_unit)
Convert duration to hour.
Definition: date.lib.php:331
BOM\fetchLinesbytypeproduct
fetchLinesbytypeproduct($typeproduct=0)
Load object lines in memory from the database by type of product.
Definition: bom.class.php:412
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4994
BOMLine\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:1983
BOMLine
Class for BOMLine.
Definition: bom.class.php:1606
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1072
BOM\create
create(User $user, $notrigger=false)
Create object into database.
Definition: bom.class.php:273
dol_dir_list
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:61
CommonObject\fetchLinesCommon
fetchLinesCommon($morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9489
BOM\calculateCosts
calculateCosts()
BOM costs calculation based on cost_price or pmp of each BOM line.
Definition: bom.class.php:1368
BOM\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:1199
BOM\getNetNeedsTree
getNetNeedsTree(&$TNetNeeds=array(), $qty=0, $level=0)
Get Net needs Tree by product or bom.
Definition: bom.class.php:1508
CommonObject\initAsSpecimenCommon
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: commonobject.class.php:9971
CommonObjectLine
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Definition: commonobjectline.class.php:32
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:45
BOMLine\__construct
__construct(DoliDB $db)
Constructor.
Definition: bom.class.php:1738
BOM
Class for BOM.
Definition: bom.class.php:36
BOM\getNextNumRef
getNextNumRef($prod)
Returns the reference to the following non used BOM depending on the active numbering module defined ...
Definition: bom.class.php:836
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5834
BOMLine\LibStatut
LibStatut($status, $mode=0)
Return the status.
Definition: bom.class.php:1996
measuringUnitString
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
Definition: product.lib.php:805
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4025
BOM\replaceProduct
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
Definition: bom.class.php:1468
BOMLine\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:2036
BOM\cancel
cancel($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:1027
CommonObject\commonGenerateDocument
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
Definition: commonobject.class.php:5460
CommonObject\createCommon
createCommon(User $user, $notrigger=false)
Create object into database.
Definition: commonobject.class.php:9266
BOM\createFromClone
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition: bom.class.php:289
BOM\addLine
addLine($fk_product, $qty, $qty_frozen=0, $disable_stock_change=0, $efficiency=1.0, $position=-1, $fk_bom_child=null, $import_key=null, $fk_unit='', $array_options=0)
Add an BOM line into database (linked to BOM)
Definition: bom.class.php:575
BOM\reopen
reopen($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:1051
BOMLine\create
create(User $user, $notrigger=false)
Create object into database.
Definition: bom.class.php:1775
BOMLine\getNomUrl
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
Definition: bom.class.php:1911
BOMLine\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bom.class.php:1879
BOMLine\info
info($id)
Load the info information in the object.
Definition: bom.class.php:2008
BOM\deleteLine
deleteLine(User $user, $idline, $notrigger=false)
Delete a line of object in database.
Definition: bom.class.php:788
BOM\getParentBomTreeRecursive
getParentBomTreeRecursive(&$TParentBom, $bom_id='', $level=1)
Recursively retrieves all parent bom in the tree that leads to the $bom_id bom.
Definition: bom.class.php:1536
CommonObject\commonReplaceProduct
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
Definition: commonobject.class.php:8599
BOM\getLinesArray
getLinesArray()
Create an array of lines.
Definition: bom.class.php:1269
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1639
BOM\getNetNeeds
getNetNeeds(&$TNetNeeds=array(), $qty=0)
Get Net needs by product.
Definition: bom.class.php:1484
BOM\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:380
BOM\__construct
__construct(DoliDB $db)
Constructor.
Definition: bom.class.php:236
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3428
BOM\validate
validate($user, $notrigger=0)
Validate bom.
Definition: bom.class.php:884
BOM\fetchAll
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
Definition: bom.class.php:468
CommonObject\updateCommon
updateCommon(User $user, $notrigger=false)
Update object into database.
Definition: commonobject.class.php:9539
BOM\doScheduledJob
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
Definition: bom.class.php:1339
BOM\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: bom.class.php:1074
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3888
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:147
ref
$object ref
Definition: info.php:78
CommonObject\fetch_product
fetch_product()
Load the product with id $this->fk_product into this->product.
Definition: commonobject.class.php:1940
User
Class to manage Dolibarr users.
Definition: user.class.php:44
BOM\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bom.class.php:538
Product
Class to manage products or services.
Definition: product.class.php:46
BOM\LibStatut
LibStatut($status, $mode=0)
Return the status.
Definition: bom.class.php:1212
BOM\setDraft
setDraft($user, $notrigger=0)
Set draft status.
Definition: bom.class.php:1003
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10767
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4361
BOM\fetchLines
fetchLines()
Load object lines in memory from the database.
Definition: bom.class.php:397
BOM\getNomUrl
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
Definition: bom.class.php:1116
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2947
BOM\info
info($id)
Load the info information in the object.
Definition: bom.class.php:1240
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5864
BOM\generateDocument
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
Definition: bom.class.php:1297
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:96
CommonObject\getFieldList
getFieldList($alias='')
Function to concat keys of fields.
Definition: commonobject.class.php:9218
BOM\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:1325
BOMLine\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:1791
BOM\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: bom.class.php:1567