dolibarr  18.0.0
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  * Copyright (C) 2023 Charlene Benke <charlene@patas-monkey.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
26 // Put here all includes required by your class file
27 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
28 require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php";
29 require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
31 //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
32 //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
33 
34 
38 class BOM extends CommonObject
39 {
40 
44  public $module = 'bom';
45 
49  public $element = 'bom';
50 
54  public $table_element = 'bom_bom';
55 
59  public $ismultientitymanaged = 1;
60 
64  public $isextrafieldmanaged = 1;
65 
69  public $picto = 'bom';
70 
71 
72  const STATUS_DRAFT = 0;
73  const STATUS_VALIDATED = 1;
74  const STATUS_CANCELED = 9;
75 
76 
103  // BEGIN MODULEBUILDER PROPERTIES
107  public $fields = array(
108  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
109  'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=> 1, 'default'=>1, 'index'=>1, 'position'=>5),
110  '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'),
111  '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'),
112  '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'),
113  //'bomtype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'position'=>32, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing')),
114  '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'),
115  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
116  'qty' => array('type'=>'real', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'position'=>55, 'notnull'=>1, 'isameasure'=>'1', 'css'=>'maxwidth50imp right'),
117  //'efficiency' => array('type'=>'real', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>-1, 'default'=>1, 'position'=>100, 'notnull'=>0, 'css'=>'maxwidth50imp', 'help'=>'ValueOfMeansLossForProductProduced'),
118  'duration' => array('type'=>'duration', 'label'=>'EstimatedDuration', 'enabled'=>1, 'visible'=>-1, 'position'=>101, 'notnull'=>-1, 'css'=>'maxwidth50imp', 'help'=>'EstimatedDurationDesc'),
119  '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'),
120  'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>-2, 'position'=>161, 'notnull'=>-1,),
121  'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>-2, 'position'=>162, 'notnull'=>-1,),
122  'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>300, 'notnull'=>1,),
123  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,),
124  'date_valid' => array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>502, 'notnull'=>0,),
125  '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'),
126  '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'),
127  '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'),
128  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
129  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
130  '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')),
131  );
132 
136  public $rowid;
137 
141  public $ref;
142 
146  public $label;
147 
151  public $bomtype;
152 
156  public $description;
157 
161  public $date_creation;
162 
166  public $date_valid;
167 
168  public $tms;
169 
173  public $fk_user_creat;
174 
178  public $fk_user_modif;
179 
183  public $fk_user_valid;
184 
188  public $fk_warehouse;
189 
193  public $import_key;
194 
198  public $status;
199 
203  public $fk_product;
204  public $qty;
205  public $duration;
206  public $efficiency;
207  // END MODULEBUILDER PROPERTIES
208 
209 
210  // If this object has a subtable with lines
211 
215  public $table_element_line = 'bom_bomline';
216 
220  public $fk_element = 'fk_bom';
221 
225  public $class_element_line = 'BOMLine';
226 
227  // /**
228  // * @var array List of child tables. To test if we can delete object.
229  // */
230  // protected $childtables=array();
231 
235  protected $childtablesoncascade = array('bom_bomline');
236 
240  public $lines = array();
241 
245  public $total_cost = 0;
246 
250  public $unit_cost = 0;
251 
252 
258  public function __construct(DoliDB $db)
259  {
260  global $conf, $langs;
261 
262  $this->db = $db;
263 
264  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
265  $this->fields['rowid']['visible'] = 0;
266  }
267  if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
268  $this->fields['entity']['enabled'] = 0;
269  }
270 
271  // Unset fields that are disabled
272  foreach ($this->fields as $key => $val) {
273  if (isset($val['enabled']) && empty($val['enabled'])) {
274  unset($this->fields[$key]);
275  }
276  }
277 
278  // Translate some data of arrayofkeyval
279  foreach ($this->fields as $key => $val) {
280  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
281  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
282  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
283  }
284  }
285  }
286  }
287 
295  public function create(User $user, $notrigger = false)
296  {
297  if ($this->efficiency <= 0 || $this->efficiency > 1) {
298  $this->efficiency = 1;
299  }
300 
301  return $this->createCommon($user, $notrigger);
302  }
303 
311  public function createFromClone(User $user, $fromid)
312  {
313  global $langs, $hookmanager, $extrafields;
314  $error = 0;
315 
316  dol_syslog(__METHOD__, LOG_DEBUG);
317 
318  $object = new self($this->db);
319 
320  $this->db->begin();
321 
322  // Load source object
323  $result = $object->fetchCommon($fromid);
324  if ($result > 0 && !empty($object->table_element_line)) {
325  $object->fetchLines();
326  }
327 
328  // Get lines so they will be clone
329  //foreach ($object->lines as $line)
330  // $line->fetch_optionals();
331 
332  // Reset some properties
333  unset($object->id);
334  unset($object->fk_user_creat);
335  unset($object->import_key);
336 
337  // Clear fields
338  $object->ref = empty($this->fields['ref']['default']) ? $langs->trans("copy_of_").$object->ref : $this->fields['ref']['default'];
339  $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
340  $object->status = self::STATUS_DRAFT;
341  // ...
342  // Clear extrafields that are unique
343  if (is_array($object->array_options) && count($object->array_options) > 0) {
344  $extrafields->fetch_name_optionals_label($object->table_element);
345  foreach ($object->array_options as $key => $option) {
346  $shortkey = preg_replace('/options_/', '', $key);
347  if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
348  //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
349  unset($object->array_options[$key]);
350  }
351  }
352  }
353 
354  // Create clone
355  $object->context['createfromclone'] = 'createfromclone';
356  $result = $object->createCommon($user);
357  if ($result < 0) {
358  $error++;
359  $this->error = $object->error;
360  $this->errors = $object->errors;
361  }
362 
363  if (!$error) {
364  // copy internal contacts
365  if ($this->copy_linked_contact($object, 'internal') < 0) {
366  $error++;
367  }
368  }
369 
370  if (!$error) {
371  // copy external contacts if same company
372  if (property_exists($this, 'socid') && $this->socid == $object->socid) {
373  if ($this->copy_linked_contact($object, 'external') < 0) {
374  $error++;
375  }
376  }
377  }
378 
379  // If there is lines, create lines too
380 
381 
382 
383  unset($object->context['createfromclone']);
384 
385  // End
386  if (!$error) {
387  $this->db->commit();
388  return $object;
389  } else {
390  $this->db->rollback();
391  return -1;
392  }
393  }
394 
402  public function fetch($id, $ref = null)
403  {
404  $result = $this->fetchCommon($id, $ref);
405 
406  if ($result > 0 && !empty($this->table_element_line)) {
407  $this->fetchLines();
408  }
409  //$this->calculateCosts(); // This consume a high number of subrequests. Do not call it into fetch but when you need it.
410 
411  return $result;
412  }
413 
419  public function fetchLines()
420  {
421  $this->lines = array();
422 
423  $result = $this->fetchLinesCommon();
424  return $result;
425  }
426 
434  public function fetchLinesbytypeproduct($typeproduct = 0)
435  {
436  $this->lines = array();
437 
438  $objectlineclassname = get_class($this).'Line';
439  if (!class_exists($objectlineclassname)) {
440  $this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon';
441  return -1;
442  }
443 
444  $objectline = new $objectlineclassname($this->db);
445 
446  $sql = "SELECT ".$objectline->getFieldList('l');
447  $sql .= " FROM ".$this->db->prefix().$objectline->table_element." as l";
448  $sql .= " LEFT JOIN ".$this->db->prefix()."product as p ON p.rowid = l.fk_product";
449  $sql .= " WHERE l.fk_".$this->db->escape($this->element)." = ".((int) $this->id);
450  $sql .= " AND p.fk_product_type = ". ((int) $typeproduct);
451  if (isset($objectline->fields['position'])) {
452  $sql .= $this->db->order('position', 'ASC');
453  }
454 
455  $resql = $this->db->query($sql);
456  if ($resql) {
457  $num_rows = $this->db->num_rows($resql);
458  $i = 0;
459  while ($i < $num_rows) {
460  $obj = $this->db->fetch_object($resql);
461  if ($obj) {
462  $newline = new $objectlineclassname($this->db);
463  $newline->setVarsFromFetchObj($obj);
464 
465  $this->lines[] = $newline;
466  }
467  $i++;
468  }
469 
470  return $num_rows;
471  } else {
472  $this->error = $this->db->lasterror();
473  $this->errors[] = $this->error;
474  return -1;
475  }
476  }
477 
478 
490  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
491  {
492  global $conf;
493 
494  dol_syslog(__METHOD__, LOG_DEBUG);
495 
496  $records = array();
497 
498  $sql = 'SELECT ';
499  $sql .= $this->getFieldList();
500  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
501  if ($this->ismultientitymanaged) {
502  $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
503  } else {
504  $sql .= ' WHERE 1 = 1';
505  }
506  // Manage filter
507  $sqlwhere = array();
508  if (count($filter) > 0) {
509  foreach ($filter as $key => $value) {
510  if ($key == 't.rowid') {
511  $sqlwhere[] = $key." = ".((int) $value);
512  } elseif (strpos($key, 'date') !== false) {
513  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
514  } elseif ($key == 'customsql') {
515  $sqlwhere[] = $value;
516  } else {
517  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
518  }
519  }
520  }
521  if (count($sqlwhere) > 0) {
522  $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
523  }
524 
525  if (!empty($sortfield)) {
526  $sql .= $this->db->order($sortfield, $sortorder);
527  }
528  if (!empty($limit)) {
529  $sql .= $this->db->plimit($limit, $offset);
530  }
531 
532  $resql = $this->db->query($sql);
533  if ($resql) {
534  $num = $this->db->num_rows($resql);
535 
536  while ($obj = $this->db->fetch_object($resql)) {
537  $record = new self($this->db);
538  $record->setVarsFromFetchObj($obj);
539 
540  $records[$record->id] = $record;
541  }
542  $this->db->free($resql);
543 
544  return $records;
545  } else {
546  $this->errors[] = 'Error '.$this->db->lasterror();
547  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
548 
549  return -1;
550  }
551  }
552 
560  public function update(User $user, $notrigger = false)
561  {
562  if ($this->efficiency <= 0 || $this->efficiency > 1) {
563  $this->efficiency = 1;
564  }
565 
566  return $this->updateCommon($user, $notrigger);
567  }
568 
576  public function delete(User $user, $notrigger = false)
577  {
578  return $this->deleteCommon($user, $notrigger);
579  //return $this->deleteCommon($user, $notrigger, 1);
580  }
581 
598  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, $fk_default_workstation = null)
599  {
600  global $mysoc, $conf, $langs, $user;
601 
602  $logtext = "::addLine bomid=$this->id, qty=$qty, fk_product=$fk_product, qty_frozen=$qty_frozen, disable_stock_change=$disable_stock_change, efficiency=$efficiency";
603  $logtext .= ", fk_bom_child=$fk_bom_child, import_key=$import_key";
604  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
605 
606  if ($this->statut == self::STATUS_DRAFT) {
607  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
608 
609  // Clean parameters
610  if (empty($qty)) {
611  $qty = 0;
612  }
613  if (empty($qty_frozen)) {
614  $qty_frozen = 0;
615  }
616  if (empty($disable_stock_change)) {
617  $disable_stock_change = 0;
618  }
619  if (empty($efficiency)) {
620  $efficiency = 1.0;
621  }
622  if (empty($fk_bom_child)) {
623  $fk_bom_child = null;
624  }
625  if (empty($import_key)) {
626  $import_key = null;
627  }
628  if (empty($position)) {
629  $position = -1;
630  }
631 
632  $qty = price2num($qty);
633  $efficiency = price2num($efficiency);
634  $position = price2num($position);
635 
636  $this->db->begin();
637 
638  // Rank to use
639  $rangMax = $this->line_max();
640  $rankToUse = $position;
641  if ($rankToUse <= 0 or $rankToUse > $rangMax) { // New line after existing lines
642  $rankToUse = $rangMax + 1;
643  } else { // New line between the existing lines
644  foreach ($this->lines as $bl) {
645  if ($bl->position >= $rankToUse) {
646  $bl->position++;
647  $bl->update($user);
648  }
649  }
650  }
651 
652  // Insert line
653  $line = new BOMLine($this->db);
654 
655  $line->context = $this->context;
656 
657  $line->fk_bom = $this->id;
658  $line->fk_product = $fk_product;
659  $line->qty = $qty;
660  $line->qty_frozen = $qty_frozen;
661  $line->disable_stock_change = $disable_stock_change;
662  $line->efficiency = $efficiency;
663  $line->fk_bom_child = $fk_bom_child;
664  $line->import_key = $import_key;
665  $line->position = $rankToUse;
666  $line->fk_unit = $fk_unit;
667  $line->fk_default_workstation = $fk_default_workstation;
668 
669  if (is_array($array_options) && count($array_options) > 0) {
670  $line->array_options = $array_options;
671  }
672 
673  $result = $line->create($user);
674 
675  if ($result > 0) {
676  $this->calculateCosts();
677  $this->db->commit();
678  return $result;
679  } else {
680  $this->setErrorsFromObject($line);
681  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
682  $this->db->rollback();
683  return -2;
684  }
685  } else {
686  dol_syslog(get_class($this)."::addLine status of BOM must be Draft to allow use of ->addLine()", LOG_ERR);
687  return -3;
688  }
689  }
690 
705  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)
706  {
707  global $mysoc, $conf, $langs, $user;
708 
709  $logtext = "::updateLine bomid=$this->id, qty=$qty, qty_frozen=$qty_frozen, disable_stock_change=$disable_stock_change, efficiency=$efficiency";
710  $logtext .= ", import_key=$import_key";
711  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
712 
713  if ($this->statut == self::STATUS_DRAFT) {
714  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
715 
716  // Clean parameters
717  if (empty($qty)) {
718  $qty = 0;
719  }
720  if (empty($qty_frozen)) {
721  $qty_frozen = 0;
722  }
723  if (empty($disable_stock_change)) {
724  $disable_stock_change = 0;
725  }
726  if (empty($efficiency)) {
727  $efficiency = 1.0;
728  }
729  if (empty($import_key)) {
730  $import_key = null;
731  }
732  if (empty($position)) {
733  $position = -1;
734  }
735 
736  $qty = price2num($qty);
737  $efficiency = price2num($efficiency);
738  $position = price2num($position);
739 
740  $this->db->begin();
741 
742  //Fetch current line from the database and then clone the object and set it in $oldline property
743  $line = new BOMLine($this->db);
744  $line->fetch($rowid);
745  $line->fetch_optionals();
746 
747  $staticLine = clone $line;
748  $line->oldcopy = $staticLine;
749  $line->context = $this->context;
750 
751  // Rank to use
752  $rankToUse = (int) $position;
753  if ($rankToUse != $line->oldcopy->position) { // check if position have a new value
754  foreach ($this->lines as $bl) {
755  if ($bl->position >= $rankToUse AND $bl->position < ($line->oldcopy->position + 1)) { // move rank up
756  $bl->position++;
757  $bl->update($user);
758  }
759  if ($bl->position <= $rankToUse AND $bl->position > ($line->oldcopy->position)) { // move rank down
760  $bl->position--;
761  $bl->update($user);
762  }
763  }
764  }
765 
766 
767  $line->fk_bom = $this->id;
768  $line->qty = $qty;
769  $line->qty_frozen = $qty_frozen;
770  $line->disable_stock_change = $disable_stock_change;
771  $line->efficiency = $efficiency;
772  $line->import_key = $import_key;
773  $line->position = $rankToUse;
774  if (!empty($fk_unit)) {
775  $line->fk_unit = $fk_unit;
776  }
777 
778  if (is_array($array_options) && count($array_options) > 0) {
779  // We replace values in this->line->array_options only for entries defined into $array_options
780  foreach ($array_options as $key => $value) {
781  $line->array_options[$key] = $array_options[$key];
782  }
783  }
784 
785  $result = $line->update($user);
786 
787  if ($result > 0) {
788  $this->calculateCosts();
789  $this->db->commit();
790  return $result;
791  } else {
792  $this->setErrorsFromObject($line);
793  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
794  $this->db->rollback();
795  return -2;
796  }
797  } else {
798  dol_syslog(get_class($this)."::addLine status of BOM must be Draft to allow use of ->addLine()", LOG_ERR);
799  return -3;
800  }
801  }
802 
811  public function deleteLine(User $user, $idline, $notrigger = false)
812  {
813  if ($this->status < 0) {
814  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
815  return -2;
816  }
817 
818  $this->db->begin();
819 
820  //Fetch current line from the database and then clone the object and set it in $oldline property
821  $line = new BOMLine($this->db);
822  $line->fetch($idline);
823  $line->fetch_optionals();
824 
825  $staticLine = clone $line;
826  $line->oldcopy = $staticLine;
827  $line->context = $this->context;
828 
829  $result = $line->delete($user, $notrigger);
830 
831  //Positions (rank) reordering
832  foreach ($this->lines as $bl) {
833  if ($bl->position > ($line->oldcopy->position)) { // move rank down
834  $bl->position--;
835  $bl->update($user);
836  }
837  }
838 
839  if ($result > 0) {
840  $this->calculateCosts();
841  $this->db->commit();
842  return $result;
843  } else {
844  $this->setErrorsFromObject($line);
845  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
846  $this->db->rollback();
847  return -2;
848  }
849  }
850 
858  public function getNextNumRef($prod)
859  {
860  global $langs, $conf;
861  $langs->load("mrp");
862 
863  if (!empty($conf->global->BOM_ADDON)) {
864  $mybool = false;
865 
866  $file = $conf->global->BOM_ADDON.".php";
867  $classname = $conf->global->BOM_ADDON;
868 
869  // Include file with class
870  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
871  foreach ($dirmodels as $reldir) {
872  $dir = dol_buildpath($reldir."core/modules/bom/");
873 
874  // Load file with numbering class (if found)
875  $mybool |= @include_once $dir.$file;
876  }
877 
878  if ($mybool === false) {
879  dol_print_error('', "Failed to include file ".$file);
880  return '';
881  }
882 
883  $obj = new $classname();
884  $numref = $obj->getNextValue($prod, $this);
885 
886  if ($numref != "") {
887  return $numref;
888  } else {
889  $this->error = $obj->error;
890  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
891  return "";
892  }
893  } else {
894  print $langs->trans("Error")." ".$langs->trans("Error_BOM_ADDON_NotDefined");
895  return "";
896  }
897  }
898 
906  public function validate($user, $notrigger = 0)
907  {
908  global $conf, $langs;
909 
910  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
911 
912  $error = 0;
913 
914  // Protection
915  if ($this->status == self::STATUS_VALIDATED) {
916  dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
917  return 0;
918  }
919 
920  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->create))
921  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
922  {
923  $this->error='NotEnoughPermissions';
924  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
925  return -1;
926  }*/
927 
928  $now = dol_now();
929 
930  $this->db->begin();
931 
932  // Define new ref
933  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
934  $this->fetch_product();
935  $num = $this->getNextNumRef($this->product);
936  } else {
937  $num = $this->ref;
938  }
939  $this->newref = dol_sanitizeFileName($num);
940 
941  // Validate
942  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
943  $sql .= " SET ref = '".$this->db->escape($num)."',";
944  $sql .= " status = ".self::STATUS_VALIDATED.",";
945  $sql .= " date_valid='".$this->db->idate($now)."',";
946  $sql .= " fk_user_valid = ".((int) $user->id);
947  $sql .= " WHERE rowid = ".((int) $this->id);
948 
949  dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
950  $resql = $this->db->query($sql);
951  if (!$resql) {
952  dol_print_error($this->db);
953  $this->error = $this->db->lasterror();
954  $error++;
955  }
956 
957  if (!$error && !$notrigger) {
958  // Call trigger
959  $result = $this->call_trigger('BOM_VALIDATE', $user);
960  if ($result < 0) {
961  $error++;
962  }
963  // End call triggers
964  }
965 
966  if (!$error) {
967  $this->oldref = $this->ref;
968 
969  // Rename directory if dir was a temporary ref
970  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
971  // Now we rename also files into index
972  $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)."'";
973  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'bom/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
974  $resql = $this->db->query($sql);
975  if (!$resql) {
976  $error++; $this->error = $this->db->lasterror();
977  }
978 
979  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
980  $oldref = dol_sanitizeFileName($this->ref);
981  $newref = dol_sanitizeFileName($num);
982  $dirsource = $conf->bom->dir_output.'/'.$oldref;
983  $dirdest = $conf->bom->dir_output.'/'.$newref;
984  if (!$error && file_exists($dirsource)) {
985  dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
986 
987  if (@rename($dirsource, $dirdest)) {
988  dol_syslog("Rename ok");
989  // Rename docs starting with $oldref with $newref
990  $listoffiles = dol_dir_list($conf->bom->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
991  foreach ($listoffiles as $fileentry) {
992  $dirsource = $fileentry['name'];
993  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
994  $dirsource = $fileentry['path'].'/'.$dirsource;
995  $dirdest = $fileentry['path'].'/'.$dirdest;
996  @rename($dirsource, $dirdest);
997  }
998  }
999  }
1000  }
1001  }
1002 
1003  // Set new ref and current status
1004  if (!$error) {
1005  $this->ref = $num;
1006  $this->status = self::STATUS_VALIDATED;
1007  }
1008 
1009  if (!$error) {
1010  $this->db->commit();
1011  return 1;
1012  } else {
1013  $this->db->rollback();
1014  return -1;
1015  }
1016  }
1017 
1025  public function setDraft($user, $notrigger = 0)
1026  {
1027  // Protection
1028  if ($this->status <= self::STATUS_DRAFT) {
1029  return 0;
1030  }
1031 
1032  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1033  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1034  {
1035  $this->error='Permission denied';
1036  return -1;
1037  }*/
1038 
1039  return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'BOM_UNVALIDATE');
1040  }
1041 
1049  public function cancel($user, $notrigger = 0)
1050  {
1051  // Protection
1052  if ($this->status != self::STATUS_VALIDATED) {
1053  return 0;
1054  }
1055 
1056  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1057  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1058  {
1059  $this->error='Permission denied';
1060  return -1;
1061  }*/
1062 
1063  return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'BOM_CLOSE');
1064  }
1065 
1073  public function reopen($user, $notrigger = 0)
1074  {
1075  // Protection
1076  if ($this->status != self::STATUS_CANCELED) {
1077  return 0;
1078  }
1079 
1080  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1081  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1082  {
1083  $this->error='Permission denied';
1084  return -1;
1085  }*/
1086 
1087  return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'BOM_REOPEN');
1088  }
1089 
1096  public function getTooltipContentArray($params)
1097  {
1098  global $conf, $langs, $user;
1099 
1100  $langs->loadLangs(['product', 'mrp']);
1101 
1102  $datas = [];
1103 
1104  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1105  return ['optimize' => $langs->trans("ShowBillOfMaterials")];
1106  }
1107  $picto = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("BillOfMaterials").'</u>';
1108  if (isset($this->status)) {
1109  $picto .= ' '.$this->getLibStatut(5);
1110  }
1111  $datas['picto'] = $picto;
1112  $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1113  if (isset($this->label)) {
1114  $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1115  }
1116  if (!empty($this->fk_product) && $this->fk_product > 0) {
1117  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1118  $product = new Product($this->db);
1119  $resultFetch = $product->fetch($this->fk_product);
1120  if ($resultFetch > 0) {
1121  $datas['product'] = "<br><b>".$langs->trans("Product").'</b>: '.$product->ref.' - '.$product->label;
1122  }
1123  }
1124 
1125  return $datas;
1126  }
1127 
1138  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1139  {
1140  global $db, $conf, $langs, $hookmanager;
1141 
1142  if (!empty($conf->dol_no_mouse_hover)) {
1143  $notooltip = 1; // Force disable tooltips
1144  }
1145 
1146  $result = '';
1147  $params = [
1148  'id' => $this->id,
1149  'objecttype' => $this->element,
1150  'option' => $option,
1151  ];
1152  $classfortooltip = 'classfortooltip';
1153  $dataparams = '';
1154  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1155  $classfortooltip = 'classforajaxtooltip';
1156  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1157  $label = '';
1158  } else {
1159  $label = implode($this->getTooltipContentArray($params));
1160  }
1161 
1162  $url = DOL_URL_ROOT.'/bom/bom_card.php?id='.$this->id;
1163 
1164  if ($option != 'nolink') {
1165  // Add param to save lastsearch_values or not
1166  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1167  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1168  $add_save_lastsearch_values = 1;
1169  }
1170  if ($add_save_lastsearch_values) {
1171  $url .= '&save_lastsearch_values=1';
1172  }
1173  }
1174 
1175  $linkclose = '';
1176  if (empty($notooltip)) {
1177  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1178  $label = $langs->trans("ShowBillOfMaterials");
1179  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1180  }
1181  $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1182  $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1183  } else {
1184  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1185  }
1186 
1187  $linkstart = '<a href="'.$url.'"';
1188  $linkstart .= $linkclose.'>';
1189  $linkend = '</a>';
1190 
1191  $result .= $linkstart;
1192  if ($withpicto) {
1193  $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
1194  }
1195  if ($withpicto != 2) {
1196  $result .= $this->ref;
1197  }
1198  $result .= $linkend;
1199  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1200 
1201  global $action, $hookmanager;
1202  $hookmanager->initHooks(array('bomdao'));
1203  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1204  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1205  if ($reshook > 0) {
1206  $result = $hookmanager->resPrint;
1207  } else {
1208  $result .= $hookmanager->resPrint;
1209  }
1210 
1211  return $result;
1212  }
1213 
1220  public function getLibStatut($mode = 0)
1221  {
1222  return $this->LibStatut($this->status, $mode);
1223  }
1224 
1225  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1233  public function LibStatut($status, $mode = 0)
1234  {
1235  // phpcs:enable
1236  if (empty($this->labelStatus)) {
1237  global $langs;
1238  //$langs->load("mrp");
1239  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1240  $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
1241  $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
1242  }
1243 
1244  $statusType = 'status'.$status;
1245  if ($status == self::STATUS_VALIDATED) {
1246  $statusType = 'status4';
1247  }
1248  if ($status == self::STATUS_CANCELED) {
1249  $statusType = 'status6';
1250  }
1251 
1252  return dolGetStatus($this->labelStatus[$status], $this->labelStatus[$status], '', $statusType, $mode);
1253  }
1254 
1261  public function info($id)
1262  {
1263  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1264  $sql .= ' fk_user_creat, fk_user_modif';
1265  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1266  $sql .= ' WHERE t.rowid = '.((int) $id);
1267  $result = $this->db->query($sql);
1268  if ($result) {
1269  if ($this->db->num_rows($result)) {
1270  $obj = $this->db->fetch_object($result);
1271  $this->id = $obj->rowid;
1272 
1273  $this->user_creation_id = $obj->fk_user_creat;
1274  $this->user_modification_id = $obj->fk_user_modif;
1275  $this->date_creation = $this->db->jdate($obj->datec);
1276  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1277  }
1278 
1279  $this->db->free($result);
1280  } else {
1281  dol_print_error($this->db);
1282  }
1283  }
1284 
1290  public function getLinesArray()
1291  {
1292  $this->lines = array();
1293 
1294  $objectline = new BOMLine($this->db);
1295  $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_bom = '.((int) $this->id)));
1296 
1297  if (is_numeric($result)) {
1298  $this->error = $objectline->error;
1299  $this->errors = $objectline->errors;
1300  return $result;
1301  } else {
1302  $this->lines = $result;
1303  return $this->lines;
1304  }
1305  }
1306 
1318  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1319  {
1320  global $conf, $langs;
1321 
1322  $langs->load("mrp");
1323  $outputlangs->load("products");
1324 
1325  if (!dol_strlen($modele)) {
1326  $modele = '';
1327 
1328  if ($this->model_pdf) {
1329  $modele = $this->model_pdf;
1330  } elseif (!empty($conf->global->BOM_ADDON_PDF)) {
1331  $modele = $conf->global->BOM_ADDON_PDF;
1332  }
1333  }
1334 
1335  $modelpath = "core/modules/bom/doc/";
1336  if (!empty($modele)) {
1337  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1338  } else {
1339  return 0;
1340  }
1341  }
1342 
1349  public function initAsSpecimen()
1350  {
1351  $this->initAsSpecimenCommon();
1352  $this->ref = 'BOM-123';
1353  $this->date = $this->date_creation;
1354  }
1355 
1356 
1363  public function doScheduledJob()
1364  {
1365  global $conf, $langs;
1366 
1367  //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1368 
1369  $error = 0;
1370  $this->output = '';
1371  $this->error = '';
1372 
1373  dol_syslog(__METHOD__, LOG_DEBUG);
1374 
1375  $now = dol_now();
1376 
1377  $this->db->begin();
1378 
1379  // ...
1380 
1381  $this->db->commit();
1382 
1383  return $error;
1384  }
1385 
1392  public function calculateCosts()
1393  {
1394  global $conf, $hookmanager;
1395 
1396  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1397  $this->unit_cost = 0;
1398  $this->total_cost = 0;
1399 
1400  $parameters=array();
1401  $reshook = $hookmanager->executeHooks('calculateCostsBom', $parameters, $this); // Note that $action and $object may have been modified by hook
1402 
1403  if ($reshook > 0) {
1404  return $hookmanager->resPrint;
1405  }
1406 
1407  if (is_array($this->lines) && count($this->lines)) {
1408  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1409  $productFournisseur = new ProductFournisseur($this->db);
1410  $tmpproduct = new Product($this->db);
1411 
1412  foreach ($this->lines as &$line) {
1413  $tmpproduct->cost_price = 0;
1414  $tmpproduct->pmp = 0;
1415  $result = $tmpproduct->fetch($line->fk_product, '', '', '', 0, 1, 1); // We discard selling price and language loading
1416 
1417  if ($tmpproduct->type == $tmpproduct::TYPE_PRODUCT) {
1418  if (empty($line->fk_bom_child)) {
1419  if ($result < 0) {
1420  $this->error = $tmpproduct->error;
1421  return -1;
1422  }
1423  $line->unit_cost = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
1424  if (empty($line->unit_cost)) {
1425  if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0) {
1426  if ($productFournisseur->fourn_remise_percent != "0") {
1427  $line->unit_cost = $productFournisseur->fourn_unitprice_with_discount;
1428  } else {
1429  $line->unit_cost = $productFournisseur->fourn_unitprice;
1430  }
1431  }
1432  }
1433 
1434  $line->total_cost = price2num($line->qty * $line->unit_cost, 'MT');
1435 
1436  $this->total_cost += $line->total_cost;
1437  } else {
1438  $bom_child = new BOM($this->db);
1439  $res = $bom_child->fetch($line->fk_bom_child);
1440  if ($res > 0) {
1441  $bom_child->calculateCosts();
1442  $line->childBom[] = $bom_child;
1443  $this->total_cost += price2num($bom_child->total_cost * $line->qty, 'MT');
1444  $this->total_cost += $line->total_cost;
1445  } else {
1446  $this->error = $bom_child->error;
1447  return -2;
1448  }
1449  }
1450  } else {
1451  // Convert qty of line into hours
1452  $unitforline = measuringUnitString($line->fk_unit, '', '', 1);
1453  $qtyhourforline = convertDurationtoHour($line->qty, $unitforline);
1454 
1455  if (isModEnabled('workstation') && !empty($tmpproduct->fk_default_workstation)) {
1456  $workstation = new Workstation($this->db);
1457  $res = $workstation->fetch($tmpproduct->fk_default_workstation);
1458 
1459  if ($res > 0) $line->total_cost = price2num($qtyhourforline * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated), 'MT');
1460  else {
1461  $this->error = $workstation->error;
1462  return -3;
1463  }
1464  } else {
1465  $defaultdurationofservice = $tmpproduct->duration;
1466  $reg = array();
1467  $qtyhourservice = 0;
1468  if (preg_match('/^(\d+)([a-z]+)$/', $defaultdurationofservice, $reg)) {
1469  $qtyhourservice = convertDurationtoHour($reg[1], $reg[2]);
1470  }
1471 
1472  if ($qtyhourservice) {
1473  $line->total_cost = price2num($qtyhourforline / $qtyhourservice * $tmpproduct->cost_price, 'MT');
1474  } else {
1475  $line->total_cost = price2num($line->qty * $tmpproduct->cost_price, 'MT');
1476  }
1477  }
1478 
1479  $this->total_cost += $line->total_cost;
1480  }
1481  }
1482 
1483  $this->total_cost = price2num($this->total_cost, 'MT');
1484 
1485  if ($this->qty > 0) {
1486  $this->unit_cost = price2num($this->total_cost / $this->qty, 'MU');
1487  } elseif ($this->qty < 0) {
1488  $this->unit_cost = price2num($this->total_cost * $this->qty, 'MU');
1489  }
1490  }
1491 
1492  return 1;
1493  }
1494 
1503  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1504  {
1505  $tables = array(
1506  'bom_bomline'
1507  );
1508 
1509  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1510  }
1511 
1519  public function getNetNeeds(&$TNetNeeds = array(), $qty = 0)
1520  {
1521  if (!empty($this->lines)) {
1522  foreach ($this->lines as $line) {
1523  if (!empty($line->childBom)) {
1524  foreach ($line->childBom as $childBom) $childBom->getNetNeeds($TNetNeeds, $line->qty*$qty);
1525  } else {
1526  if (empty($TNetNeeds[$line->fk_product])) {
1527  $TNetNeeds[$line->fk_product] = 0;
1528  }
1529  $TNetNeeds[$line->fk_product] += $line->qty*$qty;
1530  }
1531  }
1532  }
1533  }
1534 
1543  public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0)
1544  {
1545  if (!empty($this->lines)) {
1546  foreach ($this->lines as $line) {
1547  if (!empty($line->childBom)) {
1548  foreach ($line->childBom as $childBom) {
1549  $TNetNeeds[$childBom->id]['bom'] = $childBom;
1550  $TNetNeeds[$childBom->id]['parentid'] = $this->id;
1551  $TNetNeeds[$childBom->id]['qty'] = $line->qty*$qty;
1552  $TNetNeeds[$childBom->id]['level'] = $level;
1553  $childBom->getNetNeedsTree($TNetNeeds, $line->qty*$qty, $level+1);
1554  }
1555  } else {
1556  $TNetNeeds[$this->id]['product'][$line->fk_product]['qty'] += $line->qty * $qty;
1557  $TNetNeeds[$this->id]['product'][$line->fk_product]['level'] = $level;
1558  }
1559  }
1560  }
1561  }
1562 
1571  public function getParentBomTreeRecursive(&$TParentBom, $bom_id = '', $level = 1)
1572  {
1573 
1574  // Protection against infinite loop
1575  if ($level > 1000) {
1576  return;
1577  }
1578 
1579  if (empty($bom_id)) $bom_id=$this->id;
1580 
1581  $sql = 'SELECT l.fk_bom, b.label
1582  FROM '.MAIN_DB_PREFIX.'bom_bomline l
1583  INNER JOIN '.MAIN_DB_PREFIX.$this->table_element.' b ON b.rowid = l.fk_bom
1584  WHERE fk_bom_child = '.((int) $bom_id);
1585 
1586  $resql = $this->db->query($sql);
1587  if (!empty($resql)) {
1588  while ($res = $this->db->fetch_object($resql)) {
1589  $TParentBom[$res->fk_bom] = $res->fk_bom;
1590  $this->getParentBomTreeRecursive($TParentBom, $res->fk_bom, $level+1);
1591  }
1592  }
1593  }
1594 
1602  public function getKanbanView($option = '', $arraydata = null)
1603  {
1604  global $db,$langs;
1605 
1606  $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1607 
1608  $prod = new Product($db);
1609  $prod->fetch($this->fk_product);
1610 
1611  $return = '<div class="box-flex-item box-flex-grow-zero">';
1612  $return .= '<div class="info-box info-box-sm">';
1613  $return .= '<span class="info-box-icon bg-infobox-action">';
1614  $return .= img_picto('', $this->picto);
1615  $return .= '</span>';
1616  $return .= '<div class="info-box-content">';
1617  $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : '').'</span>';
1618  $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1619  if (property_exists($this, 'fields') && !empty($this->fields['bomtype']['arrayofkeyval'])) {
1620  $return .= '<br><span class="info-box-label opacitymedium">'.$langs->trans("Type").' : </span>';
1621  if ($this->bomtype == 0) {
1622  $return .= '<span class="info-box-label">'.$this->fields['bomtype']['arrayofkeyval'][0].'</span>';
1623  } else {
1624  $return .= '<span class="info-box-label">'.$this->fields['bomtype']['arrayofkeyval'][1].'</span>';
1625  }
1626  }
1627  if (property_exists($this, 'fk_product') && !is_null($this->fk_product)) {
1628  $return .= '<br><span class="info-box-label">'.$prod->getNomUrl(1).'</span>';
1629  }
1630  if (method_exists($this, 'getLibStatut')) {
1631  $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3).'</div>';
1632  }
1633 
1634  $return .= '</div>';
1635  $return .= '</div>';
1636  $return .= '</div>';
1637  return $return;
1638  }
1639 }
1640 
1641 
1646 {
1650  public $element = 'bomline';
1651 
1655  public $table_element = 'bom_bomline';
1656 
1660  public $ismultientitymanaged = 0;
1661 
1665  public $isextrafieldmanaged = 1;
1666 
1670  public $picto = 'bomline';
1671 
1672 
1692  // BEGIN MODULEBUILDER PROPERTIES
1696  public $fields = array(
1697  'rowid' => array('type'=>'integer', 'label'=>'LineID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
1698  'fk_bom' => array('type'=>'integer:BillOfMaterials:societe/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1,),
1699  'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
1700  'fk_bom_child' => array('type'=>'integer:BOM:bom/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>-1, 'position'=>40, 'notnull'=>-1,),
1701  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
1702  'qty' => array('type'=>'double(24,8)', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'position'=>100, 'notnull'=>1, 'isameasure'=>'1',),
1703  'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
1704  'disable_stock_change' => array('type'=>'smallint', 'label'=>'DisableStockChange', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>108, 'css'=>'maxwidth50imp', 'help'=>'DisableStockChangeHelp'),
1705  'efficiency' => array('type'=>'double(24,8)', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'position'=>110, 'notnull'=>1, 'css'=>'maxwidth50imp', 'help'=>'ValueOfEfficiencyConsumedMeans'),
1706  'fk_unit' => array('type'=>'integer', 'label'=>'Unit', 'enabled'=>1, 'visible'=>1, 'position'=>120, 'notnull'=>-1,),
1707  'position' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>1, 'visible'=>0, 'default'=>0, 'position'=>200, 'notnull'=>1,),
1708  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
1709  'fk_default_workstation' =>array('type'=>'integer', 'label'=>'DefaultWorkstation', 'enabled'=>1, 'visible'=>1, 'notnull'=>0, 'position'=>1050)
1710  );
1711 
1715  public $rowid;
1716 
1720  public $fk_bom;
1721 
1725  public $fk_product;
1726 
1730  public $fk_bom_child;
1731 
1735  public $description;
1736  public $qty;
1737 
1741  public $qty_frozen;
1742  public $disable_stock_change;
1743  public $efficiency;
1744 
1748  public $position;
1749 
1753  public $import_key;
1754  // END MODULEBUILDER PROPERTIES
1755 
1759  public $total_cost = 0;
1760 
1764  public $unit_cost = 0;
1765 
1766 
1770  public $childBom = array();
1771 
1775  public $fk_default_workstation;
1776 
1777 
1778 
1784  public function __construct(DoliDB $db)
1785  {
1786  global $conf, $langs;
1787 
1788  $this->db = $db;
1789 
1790  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
1791  $this->fields['rowid']['visible'] = 0;
1792  }
1793  if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
1794  $this->fields['entity']['enabled'] = 0;
1795  }
1796 
1797  // Unset fields that are disabled
1798  foreach ($this->fields as $key => $val) {
1799  if (isset($val['enabled']) && empty($val['enabled'])) {
1800  unset($this->fields[$key]);
1801  }
1802  }
1803 
1804  // Translate some data of arrayofkeyval
1805  foreach ($this->fields as $key => $val) {
1806  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
1807  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
1808  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
1809  }
1810  }
1811  }
1812  }
1813 
1821  public function create(User $user, $notrigger = false)
1822  {
1823  if ($this->efficiency < 0 || $this->efficiency > 1) {
1824  $this->efficiency = 1;
1825  }
1826 
1827  return $this->createCommon($user, $notrigger);
1828  }
1829 
1837  public function fetch($id, $ref = null)
1838  {
1839  $result = $this->fetchCommon($id, $ref);
1840  //if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
1841  return $result;
1842  }
1843 
1855  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
1856  {
1857  global $conf;
1858 
1859  dol_syslog(__METHOD__, LOG_DEBUG);
1860 
1861  $records = array();
1862 
1863  $sql = 'SELECT ';
1864  $sql .= $this->getFieldList();
1865  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1866  if ($this->ismultientitymanaged) {
1867  $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
1868  } else {
1869  $sql .= ' WHERE 1 = 1';
1870  }
1871  // Manage filter
1872  $sqlwhere = array();
1873  if (count($filter) > 0) {
1874  foreach ($filter as $key => $value) {
1875  if ($key == 't.rowid') {
1876  $sqlwhere[] = $key." = ".((int) $value);
1877  } elseif (strpos($key, 'date') !== false) {
1878  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
1879  } elseif ($key == 'customsql') {
1880  $sqlwhere[] = $value;
1881  } else {
1882  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
1883  }
1884  }
1885  }
1886  if (count($sqlwhere) > 0) {
1887  $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
1888  }
1889 
1890  if (!empty($sortfield)) {
1891  $sql .= $this->db->order($sortfield, $sortorder);
1892  }
1893  if (!empty($limit)) {
1894  $sql .= $this->db->plimit($limit, $offset);
1895  }
1896 
1897  $resql = $this->db->query($sql);
1898  if ($resql) {
1899  $num = $this->db->num_rows($resql);
1900 
1901  while ($obj = $this->db->fetch_object($resql)) {
1902  $record = new self($this->db);
1903  $record->setVarsFromFetchObj($obj);
1904 
1905  $records[$record->id] = $record;
1906  }
1907  $this->db->free($resql);
1908 
1909  return $records;
1910  } else {
1911  $this->errors[] = 'Error '.$this->db->lasterror();
1912  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1913 
1914  return -1;
1915  }
1916  }
1917 
1925  public function update(User $user, $notrigger = false)
1926  {
1927  if ($this->efficiency < 0 || $this->efficiency > 1) {
1928  $this->efficiency = 1;
1929  }
1930 
1931  return $this->updateCommon($user, $notrigger);
1932  }
1933 
1941  public function delete(User $user, $notrigger = false)
1942  {
1943  return $this->deleteCommon($user, $notrigger);
1944  //return $this->deleteCommon($user, $notrigger, 1);
1945  }
1946 
1957  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1958  {
1959  global $db, $conf, $langs, $hookmanager;
1960 
1961  if (!empty($conf->dol_no_mouse_hover)) {
1962  $notooltip = 1; // Force disable tooltips
1963  }
1964 
1965  $result = '';
1966 
1967  $label = '<u>'.$langs->trans("BillOfMaterialsLine").'</u>';
1968  $label .= '<br>';
1969  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1970 
1971  $url = DOL_URL_ROOT.'/bom/bomline_card.php?id='.$this->id;
1972 
1973  if ($option != 'nolink') {
1974  // Add param to save lastsearch_values or not
1975  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1976  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1977  $add_save_lastsearch_values = 1;
1978  }
1979  if ($add_save_lastsearch_values) {
1980  $url .= '&save_lastsearch_values=1';
1981  }
1982  }
1983 
1984  $linkclose = '';
1985  if (empty($notooltip)) {
1986  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1987  $label = $langs->trans("ShowBillOfMaterialsLine");
1988  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1989  }
1990  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1991  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1992  } else {
1993  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1994  }
1995 
1996  $linkstart = '<a href="'.$url.'"';
1997  $linkstart .= $linkclose.'>';
1998  $linkend = '</a>';
1999 
2000  $result .= $linkstart;
2001  if ($withpicto) {
2002  $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);
2003  }
2004  if ($withpicto != 2) {
2005  $result .= $this->ref;
2006  }
2007  $result .= $linkend;
2008  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
2009 
2010  global $action, $hookmanager;
2011  $hookmanager->initHooks(array('bomlinedao'));
2012  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
2013  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2014  if ($reshook > 0) {
2015  $result = $hookmanager->resPrint;
2016  } else {
2017  $result .= $hookmanager->resPrint;
2018  }
2019 
2020  return $result;
2021  }
2022 
2029  public function getLibStatut($mode = 0)
2030  {
2031  return $this->LibStatut($this->status, $mode);
2032  }
2033 
2034  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2042  public function LibStatut($status, $mode = 0)
2043  {
2044  // phpcs:enable
2045  return '';
2046  }
2047 
2054  public function info($id)
2055  {
2056  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
2057  $sql .= ' fk_user_creat, fk_user_modif';
2058  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
2059  $sql .= ' WHERE t.rowid = '.((int) $id);
2060  $result = $this->db->query($sql);
2061  if ($result) {
2062  if ($this->db->num_rows($result)) {
2063  $obj = $this->db->fetch_object($result);
2064  $this->id = $obj->rowid;
2065  $this->user_creation_id = $obj->fk_user_creat;
2066  $this->user_modification_id = $obj->fk_user_modif;
2067  $this->date_creation = $this->db->jdate($obj->datec);
2068  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
2069  }
2070  $this->db->free($result);
2071  } else {
2072  dol_print_error($this->db);
2073  }
2074  }
2075 
2082  public function initAsSpecimen()
2083  {
2084  $this->initAsSpecimenCommon();
2085  }
2086 }
CommonObject\deleteCommon
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
Definition: commonobject.class.php:9574
CommonObject\setStatusCommon
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
Definition: commonobject.class.php:9852
CommonObject\fetchCommon
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9364
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1323
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:705
CommonObject\copy_linked_contact
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
Definition: commonobject.class.php:1120
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:1855
ProductFournisseur
Class to manage predefined suppliers products.
Definition: fournisseur.product.class.php:40
Workstation
Class for Workstation.
Definition: workstation.class.php:32
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:434
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:5107
CommonObject\setErrorsFromObject
setErrorsFromObject($object)
setErrorsFromObject
Definition: commonobject.class.php:731
BOMLine\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:2029
BOMLine
Class for BOMLine.
Definition: bom.class.php:1645
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1158
BOM\create
create(User $user, $notrigger=false)
Create object into database.
Definition: bom.class.php:295
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:62
CommonObject\fetchLinesCommon
fetchLinesCommon($morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9420
BOM\calculateCosts
calculateCosts()
BOM costs calculation based on cost_price or pmp of each BOM line.
Definition: bom.class.php:1392
BOM\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:1220
BOM\getNetNeedsTree
getNetNeedsTree(&$TNetNeeds=array(), $qty=0, $level=0)
Get Net needs Tree by product or bom.
Definition: bom.class.php:1543
CommonObject\initAsSpecimenCommon
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: commonobject.class.php:9902
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:1784
BOM
Class for BOM.
Definition: bom.class.php:38
BOM\getNextNumRef
getNextNumRef($prod)
Returns the reference to the following non used BOM depending on the active numbering module defined ...
Definition: bom.class.php:858
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5955
BOMLine\LibStatut
LibStatut($status, $mode=0)
Return the status.
Definition: bom.class.php:2042
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:4135
BOM\replaceProduct
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
Definition: bom.class.php:1503
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, $fk_default_workstation=null)
Add an BOM line into database (linked to BOM)
Definition: bom.class.php:598
BOMLine\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:2082
BOM\cancel
cancel($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:1049
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:5361
CommonObject\createCommon
createCommon(User $user, $notrigger=false)
Create object into database.
Definition: commonobject.class.php:9197
BOM\createFromClone
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition: bom.class.php:311
BOM\reopen
reopen($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:1073
BOMLine\create
create(User $user, $notrigger=false)
Create object into database.
Definition: bom.class.php:1821
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:1957
BOMLine\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bom.class.php:1925
BOMLine\info
info($id)
Load the info information in the object.
Definition: bom.class.php:2054
BOM\deleteLine
deleteLine(User $user, $idline, $notrigger=false)
Delete a line of object in database.
Definition: bom.class.php:811
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:1571
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:8533
BOM\getLinesArray
getLinesArray()
Create an array of lines.
Definition: bom.class.php:1290
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
BOM\getNetNeeds
getNetNeeds(&$TNetNeeds=array(), $qty=0)
Get Net needs by product.
Definition: bom.class.php:1519
BOM\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:402
BOM\__construct
__construct(DoliDB $db)
Constructor.
Definition: bom.class.php:258
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3317
BOM\validate
validate($user, $notrigger=0)
Validate bom.
Definition: bom.class.php:906
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:490
CommonObject\updateCommon
updateCommon(User $user, $notrigger=false)
Update object into database.
Definition: commonobject.class.php:9470
BOM\doScheduledJob
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
Definition: bom.class.php:1363
BOM\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: bom.class.php:1096
$sql
if(isModEnabled('facture') && $user->hasRight('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') && $user->hasRight('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:746
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3997
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
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:1789
User
Class to manage Dolibarr users.
Definition: user.class.php:47
BOM\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bom.class.php:560
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:1233
BOM\setDraft
setDraft($user, $notrigger=0)
Set draft status.
Definition: bom.class.php:1025
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10967
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:4473
BOM\fetchLines
fetchLines()
Load object lines in memory from the database.
Definition: bom.class.php:419
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:1138
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3056
BOM\info
info($id)
Load the info information in the object.
Definition: bom.class.php:1261
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5770
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:1318
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
CommonObject\getFieldList
getFieldList($alias='')
Function to concat keys of fields.
Definition: commonobject.class.php:9149
BOM\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:1349
BOMLine\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:1837
BOM\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: bom.class.php:1602