dolibarr  19.0.0-dev
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.'/core/lib/date.lib.php';
30 
31 if (isModEnabled('workstation')) {
32  require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
33 }
34 
35 //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
36 //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
37 
38 
42 class BOM extends CommonObject
43 {
44 
48  public $module = 'bom';
49 
53  public $element = 'bom';
54 
58  public $table_element = 'bom_bom';
59 
63  public $ismultientitymanaged = 1;
64 
68  public $isextrafieldmanaged = 1;
69 
73  public $picto = 'bom';
74 
75 
76  const STATUS_DRAFT = 0;
77  const STATUS_VALIDATED = 1;
78  const STATUS_CANCELED = 9;
79 
80 
107  // BEGIN MODULEBUILDER PROPERTIES
111  public $fields = array(
112  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
113  'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=> 1, 'default'=>1, 'index'=>1, 'position'=>5),
114  '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'),
115  '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'),
116  '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'),
117  //'bomtype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'position'=>32, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing')),
118  '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'),
119  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
120  'qty' => array('type'=>'real', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'position'=>55, 'notnull'=>1, 'isameasure'=>'1', 'css'=>'maxwidth50imp right'),
121  //'efficiency' => array('type'=>'real', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>-1, 'default'=>1, 'position'=>100, 'notnull'=>0, 'css'=>'maxwidth50imp', 'help'=>'ValueOfMeansLossForProductProduced'),
122  'duration' => array('type'=>'duration', 'label'=>'EstimatedDuration', 'enabled'=>1, 'visible'=>-1, 'position'=>101, 'notnull'=>-1, 'css'=>'maxwidth50imp', 'help'=>'EstimatedDurationDesc'),
123  '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'),
124  'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>-2, 'position'=>161, 'notnull'=>-1,),
125  'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>-2, 'position'=>162, 'notnull'=>-1,),
126  'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>300, 'notnull'=>1,),
127  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,),
128  'date_valid' => array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>502, 'notnull'=>0,),
129  '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'),
130  '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'),
131  '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'),
132  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
133  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
134  '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')),
135  );
136 
140  public $rowid;
141 
145  public $ref;
146 
150  public $label;
151 
155  public $bomtype;
156 
160  public $description;
161 
165  public $date_creation;
166 
170  public $date_valid;
171 
172  public $tms;
173 
177  public $fk_user_creat;
178 
182  public $fk_user_modif;
183 
187  public $fk_user_valid;
188 
192  public $fk_warehouse;
193 
197  public $import_key;
198 
202  public $status;
203 
207  public $fk_product;
208  public $qty;
209  public $duration;
210  public $efficiency;
211  // END MODULEBUILDER PROPERTIES
212 
213 
214  // If this object has a subtable with lines
215 
219  public $table_element_line = 'bom_bomline';
220 
224  public $fk_element = 'fk_bom';
225 
229  public $class_element_line = 'BOMLine';
230 
231  // /**
232  // * @var array List of child tables. To test if we can delete object.
233  // */
234  // protected $childtables=array();
235 
239  protected $childtablesoncascade = array('bom_bomline');
240 
244  public $lines = array();
245 
249  public $total_cost = 0;
250 
254  public $unit_cost = 0;
255 
256 
262  public function __construct(DoliDB $db)
263  {
264  global $conf, $langs;
265 
266  $this->db = $db;
267 
268  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
269  $this->fields['rowid']['visible'] = 0;
270  }
271  if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
272  $this->fields['entity']['enabled'] = 0;
273  }
274 
275  // Unset fields that are disabled
276  foreach ($this->fields as $key => $val) {
277  if (isset($val['enabled']) && empty($val['enabled'])) {
278  unset($this->fields[$key]);
279  }
280  }
281 
282  // Translate some data of arrayofkeyval
283  foreach ($this->fields as $key => $val) {
284  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
285  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
286  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
287  }
288  }
289  }
290  }
291 
299  public function create(User $user, $notrigger = false)
300  {
301  if ($this->efficiency <= 0 || $this->efficiency > 1) {
302  $this->efficiency = 1;
303  }
304 
305  return $this->createCommon($user, $notrigger);
306  }
307 
315  public function createFromClone(User $user, $fromid)
316  {
317  global $langs, $hookmanager, $extrafields;
318  $error = 0;
319 
320  dol_syslog(__METHOD__, LOG_DEBUG);
321 
322  $object = new self($this->db);
323 
324  $this->db->begin();
325 
326  // Load source object
327  $result = $object->fetchCommon($fromid);
328  if ($result > 0 && !empty($object->table_element_line)) {
329  $object->fetchLines();
330  }
331 
332  // Get lines so they will be clone
333  //foreach ($object->lines as $line)
334  // $line->fetch_optionals();
335 
336  // Reset some properties
337  unset($object->id);
338  unset($object->fk_user_creat);
339  unset($object->import_key);
340 
341  // Clear fields
342  $object->ref = empty($this->fields['ref']['default']) ? $langs->trans("copy_of_").$object->ref : $this->fields['ref']['default'];
343  $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
344  $object->status = self::STATUS_DRAFT;
345  // ...
346  // Clear extrafields that are unique
347  if (is_array($object->array_options) && count($object->array_options) > 0) {
348  $extrafields->fetch_name_optionals_label($object->table_element);
349  foreach ($object->array_options as $key => $option) {
350  $shortkey = preg_replace('/options_/', '', $key);
351  if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
352  //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
353  unset($object->array_options[$key]);
354  }
355  }
356  }
357 
358  // Create clone
359  $object->context['createfromclone'] = 'createfromclone';
360  $result = $object->createCommon($user);
361  if ($result < 0) {
362  $error++;
363  $this->error = $object->error;
364  $this->errors = $object->errors;
365  }
366 
367  if (!$error) {
368  // copy internal contacts
369  if ($this->copy_linked_contact($object, 'internal') < 0) {
370  $error++;
371  }
372  }
373 
374  if (!$error) {
375  // copy external contacts if same company
376  if (property_exists($this, 'socid') && $this->socid == $object->socid) {
377  if ($this->copy_linked_contact($object, 'external') < 0) {
378  $error++;
379  }
380  }
381  }
382 
383  // If there is lines, create lines too
384 
385 
386 
387  unset($object->context['createfromclone']);
388 
389  // End
390  if (!$error) {
391  $this->db->commit();
392  return $object;
393  } else {
394  $this->db->rollback();
395  return -1;
396  }
397  }
398 
406  public function fetch($id, $ref = null)
407  {
408  $result = $this->fetchCommon($id, $ref);
409 
410  if ($result > 0 && !empty($this->table_element_line)) {
411  $this->fetchLines();
412  }
413  //$this->calculateCosts(); // This consume a high number of subrequests. Do not call it into fetch but when you need it.
414 
415  return $result;
416  }
417 
423  public function fetchLines()
424  {
425  $this->lines = array();
426 
427  $result = $this->fetchLinesCommon();
428  return $result;
429  }
430 
438  public function fetchLinesbytypeproduct($typeproduct = 0)
439  {
440  $this->lines = array();
441 
442  $objectlineclassname = get_class($this).'Line';
443  if (!class_exists($objectlineclassname)) {
444  $this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon';
445  return -1;
446  }
447 
448  $objectline = new $objectlineclassname($this->db);
449 
450  $sql = "SELECT ".$objectline->getFieldList('l');
451  $sql .= " FROM ".$this->db->prefix().$objectline->table_element." as l";
452  $sql .= " LEFT JOIN ".$this->db->prefix()."product as p ON p.rowid = l.fk_product";
453  $sql .= " WHERE l.fk_".$this->db->escape($this->element)." = ".((int) $this->id);
454  $sql .= " AND p.fk_product_type = ". ((int) $typeproduct);
455  if (isset($objectline->fields['position'])) {
456  $sql .= $this->db->order('position', 'ASC');
457  }
458 
459  $resql = $this->db->query($sql);
460  if ($resql) {
461  $num_rows = $this->db->num_rows($resql);
462  $i = 0;
463  while ($i < $num_rows) {
464  $obj = $this->db->fetch_object($resql);
465  if ($obj) {
466  $newline = new $objectlineclassname($this->db);
467  $newline->setVarsFromFetchObj($obj);
468 
469  $this->lines[] = $newline;
470  }
471  $i++;
472  }
473 
474  return $num_rows;
475  } else {
476  $this->error = $this->db->lasterror();
477  $this->errors[] = $this->error;
478  return -1;
479  }
480  }
481 
482 
494  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
495  {
496  global $conf;
497 
498  dol_syslog(__METHOD__, LOG_DEBUG);
499 
500  $records = array();
501 
502  $sql = 'SELECT ';
503  $sql .= $this->getFieldList();
504  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
505  if ($this->ismultientitymanaged) {
506  $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
507  } else {
508  $sql .= ' WHERE 1 = 1';
509  }
510  // Manage filter
511  $sqlwhere = array();
512  if (count($filter) > 0) {
513  foreach ($filter as $key => $value) {
514  if ($key == 't.rowid') {
515  $sqlwhere[] = $key." = ".((int) $value);
516  } elseif (strpos($key, 'date') !== false) {
517  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
518  } elseif ($key == 'customsql') {
519  $sqlwhere[] = $value;
520  } else {
521  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
522  }
523  }
524  }
525  if (count($sqlwhere) > 0) {
526  $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
527  }
528 
529  if (!empty($sortfield)) {
530  $sql .= $this->db->order($sortfield, $sortorder);
531  }
532  if (!empty($limit)) {
533  $sql .= $this->db->plimit($limit, $offset);
534  }
535 
536  $resql = $this->db->query($sql);
537  if ($resql) {
538  $num = $this->db->num_rows($resql);
539 
540  while ($obj = $this->db->fetch_object($resql)) {
541  $record = new self($this->db);
542  $record->setVarsFromFetchObj($obj);
543 
544  $records[$record->id] = $record;
545  }
546  $this->db->free($resql);
547 
548  return $records;
549  } else {
550  $this->errors[] = 'Error '.$this->db->lasterror();
551  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
552 
553  return -1;
554  }
555  }
556 
564  public function update(User $user, $notrigger = false)
565  {
566  if ($this->efficiency <= 0 || $this->efficiency > 1) {
567  $this->efficiency = 1;
568  }
569 
570  return $this->updateCommon($user, $notrigger);
571  }
572 
580  public function delete(User $user, $notrigger = false)
581  {
582  return $this->deleteCommon($user, $notrigger);
583  //return $this->deleteCommon($user, $notrigger, 1);
584  }
585 
602  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)
603  {
604  global $mysoc, $conf, $langs, $user;
605 
606  $logtext = "::addLine bomid=$this->id, qty=$qty, fk_product=$fk_product, qty_frozen=$qty_frozen, disable_stock_change=$disable_stock_change, efficiency=$efficiency";
607  $logtext .= ", fk_bom_child=$fk_bom_child, import_key=$import_key";
608  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
609 
610  if ($this->statut == self::STATUS_DRAFT) {
611  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
612 
613  // Clean parameters
614  if (empty($qty)) {
615  $qty = 0;
616  }
617  if (empty($qty_frozen)) {
618  $qty_frozen = 0;
619  }
620  if (empty($disable_stock_change)) {
621  $disable_stock_change = 0;
622  }
623  if (empty($efficiency)) {
624  $efficiency = 1.0;
625  }
626  if (empty($fk_bom_child)) {
627  $fk_bom_child = null;
628  }
629  if (empty($import_key)) {
630  $import_key = null;
631  }
632  if (empty($position)) {
633  $position = -1;
634  }
635 
636  $qty = price2num($qty);
637  $efficiency = price2num($efficiency);
638  $position = price2num($position);
639 
640  $this->db->begin();
641 
642  // Rank to use
643  $rangMax = $this->line_max();
644  $rankToUse = $position;
645  if ($rankToUse <= 0 or $rankToUse > $rangMax) { // New line after existing lines
646  $rankToUse = $rangMax + 1;
647  } else { // New line between the existing lines
648  foreach ($this->lines as $bl) {
649  if ($bl->position >= $rankToUse) {
650  $bl->position++;
651  $bl->update($user);
652  }
653  }
654  }
655 
656  // Insert line
657  $line = new BOMLine($this->db);
658 
659  $line->context = $this->context;
660 
661  $line->fk_bom = $this->id;
662  $line->fk_product = $fk_product;
663  $line->qty = $qty;
664  $line->qty_frozen = $qty_frozen;
665  $line->disable_stock_change = $disable_stock_change;
666  $line->efficiency = $efficiency;
667  $line->fk_bom_child = $fk_bom_child;
668  $line->import_key = $import_key;
669  $line->position = $rankToUse;
670  $line->fk_unit = $fk_unit;
671  $line->fk_default_workstation = $fk_default_workstation;
672 
673  if (is_array($array_options) && count($array_options) > 0) {
674  $line->array_options = $array_options;
675  }
676 
677  $result = $line->create($user);
678 
679  if ($result > 0) {
680  $this->calculateCosts();
681  $this->db->commit();
682  return $result;
683  } else {
684  $this->setErrorsFromObject($line);
685  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
686  $this->db->rollback();
687  return -2;
688  }
689  } else {
690  dol_syslog(get_class($this)."::addLine status of BOM must be Draft to allow use of ->addLine()", LOG_ERR);
691  return -3;
692  }
693  }
694 
709  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)
710  {
711  global $mysoc, $conf, $langs, $user;
712 
713  $logtext = "::updateLine bomid=$this->id, qty=$qty, qty_frozen=$qty_frozen, disable_stock_change=$disable_stock_change, efficiency=$efficiency";
714  $logtext .= ", import_key=$import_key";
715  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
716 
717  if ($this->statut == self::STATUS_DRAFT) {
718  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
719 
720  // Clean parameters
721  if (empty($qty)) {
722  $qty = 0;
723  }
724  if (empty($qty_frozen)) {
725  $qty_frozen = 0;
726  }
727  if (empty($disable_stock_change)) {
728  $disable_stock_change = 0;
729  }
730  if (empty($efficiency)) {
731  $efficiency = 1.0;
732  }
733  if (empty($import_key)) {
734  $import_key = null;
735  }
736  if (empty($position)) {
737  $position = -1;
738  }
739 
740  $qty = price2num($qty);
741  $efficiency = price2num($efficiency);
742  $position = price2num($position);
743 
744  $this->db->begin();
745 
746  //Fetch current line from the database and then clone the object and set it in $oldline property
747  $line = new BOMLine($this->db);
748  $line->fetch($rowid);
749  $line->fetch_optionals();
750 
751  $staticLine = clone $line;
752  $line->oldcopy = $staticLine;
753  $line->context = $this->context;
754 
755  // Rank to use
756  $rankToUse = (int) $position;
757  if ($rankToUse != $line->oldcopy->position) { // check if position have a new value
758  foreach ($this->lines as $bl) {
759  if ($bl->position >= $rankToUse AND $bl->position < ($line->oldcopy->position + 1)) { // move rank up
760  $bl->position++;
761  $bl->update($user);
762  }
763  if ($bl->position <= $rankToUse AND $bl->position > ($line->oldcopy->position)) { // move rank down
764  $bl->position--;
765  $bl->update($user);
766  }
767  }
768  }
769 
770 
771  $line->fk_bom = $this->id;
772  $line->qty = $qty;
773  $line->qty_frozen = $qty_frozen;
774  $line->disable_stock_change = $disable_stock_change;
775  $line->efficiency = $efficiency;
776  $line->import_key = $import_key;
777  $line->position = $rankToUse;
778  if (!empty($fk_unit)) {
779  $line->fk_unit = $fk_unit;
780  }
781 
782  if (is_array($array_options) && count($array_options) > 0) {
783  // We replace values in this->line->array_options only for entries defined into $array_options
784  foreach ($array_options as $key => $value) {
785  $line->array_options[$key] = $array_options[$key];
786  }
787  }
788 
789  $result = $line->update($user);
790 
791  if ($result > 0) {
792  $this->calculateCosts();
793  $this->db->commit();
794  return $result;
795  } else {
796  $this->setErrorsFromObject($line);
797  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
798  $this->db->rollback();
799  return -2;
800  }
801  } else {
802  dol_syslog(get_class($this)."::addLine status of BOM must be Draft to allow use of ->addLine()", LOG_ERR);
803  return -3;
804  }
805  }
806 
815  public function deleteLine(User $user, $idline, $notrigger = false)
816  {
817  if ($this->status < 0) {
818  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
819  return -2;
820  }
821 
822  $this->db->begin();
823 
824  //Fetch current line from the database and then clone the object and set it in $oldline property
825  $line = new BOMLine($this->db);
826  $line->fetch($idline);
827  $line->fetch_optionals();
828 
829  $staticLine = clone $line;
830  $line->oldcopy = $staticLine;
831  $line->context = $this->context;
832 
833  $result = $line->delete($user, $notrigger);
834 
835  //Positions (rank) reordering
836  foreach ($this->lines as $bl) {
837  if ($bl->position > ($line->oldcopy->position)) { // move rank down
838  $bl->position--;
839  $bl->update($user);
840  }
841  }
842 
843  if ($result > 0) {
844  $this->calculateCosts();
845  $this->db->commit();
846  return $result;
847  } else {
848  $this->setErrorsFromObject($line);
849  dol_syslog(get_class($this)."::addLine error=".$this->error, LOG_ERR);
850  $this->db->rollback();
851  return -2;
852  }
853  }
854 
862  public function getNextNumRef($prod)
863  {
864  global $langs, $conf;
865  $langs->load("mrp");
866 
867  if (!empty($conf->global->BOM_ADDON)) {
868  $mybool = false;
869 
870  $file = $conf->global->BOM_ADDON.".php";
871  $classname = $conf->global->BOM_ADDON;
872 
873  // Include file with class
874  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
875  foreach ($dirmodels as $reldir) {
876  $dir = dol_buildpath($reldir."core/modules/bom/");
877 
878  // Load file with numbering class (if found)
879  $mybool |= @include_once $dir.$file;
880  }
881 
882  if ($mybool === false) {
883  dol_print_error('', "Failed to include file ".$file);
884  return '';
885  }
886 
887  $obj = new $classname();
888  $numref = $obj->getNextValue($prod, $this);
889 
890  if ($numref != "") {
891  return $numref;
892  } else {
893  $this->error = $obj->error;
894  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
895  return "";
896  }
897  } else {
898  print $langs->trans("Error")." ".$langs->trans("Error_BOM_ADDON_NotDefined");
899  return "";
900  }
901  }
902 
910  public function validate($user, $notrigger = 0)
911  {
912  global $conf, $langs;
913 
914  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
915 
916  $error = 0;
917 
918  // Protection
919  if ($this->status == self::STATUS_VALIDATED) {
920  dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
921  return 0;
922  }
923 
924  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->create))
925  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
926  {
927  $this->error='NotEnoughPermissions';
928  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
929  return -1;
930  }*/
931 
932  $now = dol_now();
933 
934  $this->db->begin();
935 
936  // Define new ref
937  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
938  $this->fetch_product();
939  $num = $this->getNextNumRef($this->product);
940  } else {
941  $num = $this->ref;
942  }
943  $this->newref = dol_sanitizeFileName($num);
944 
945  // Validate
946  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
947  $sql .= " SET ref = '".$this->db->escape($num)."',";
948  $sql .= " status = ".self::STATUS_VALIDATED.",";
949  $sql .= " date_valid='".$this->db->idate($now)."',";
950  $sql .= " fk_user_valid = ".((int) $user->id);
951  $sql .= " WHERE rowid = ".((int) $this->id);
952 
953  dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
954  $resql = $this->db->query($sql);
955  if (!$resql) {
956  dol_print_error($this->db);
957  $this->error = $this->db->lasterror();
958  $error++;
959  }
960 
961  if (!$error && !$notrigger) {
962  // Call trigger
963  $result = $this->call_trigger('BOM_VALIDATE', $user);
964  if ($result < 0) {
965  $error++;
966  }
967  // End call triggers
968  }
969 
970  if (!$error) {
971  $this->oldref = $this->ref;
972 
973  // Rename directory if dir was a temporary ref
974  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
975  // Now we rename also files into index
976  $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)."'";
977  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'bom/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
978  $resql = $this->db->query($sql);
979  if (!$resql) {
980  $error++; $this->error = $this->db->lasterror();
981  }
982 
983  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
984  $oldref = dol_sanitizeFileName($this->ref);
985  $newref = dol_sanitizeFileName($num);
986  $dirsource = $conf->bom->dir_output.'/'.$oldref;
987  $dirdest = $conf->bom->dir_output.'/'.$newref;
988  if (!$error && file_exists($dirsource)) {
989  dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
990 
991  if (@rename($dirsource, $dirdest)) {
992  dol_syslog("Rename ok");
993  // Rename docs starting with $oldref with $newref
994  $listoffiles = dol_dir_list($conf->bom->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
995  foreach ($listoffiles as $fileentry) {
996  $dirsource = $fileentry['name'];
997  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
998  $dirsource = $fileentry['path'].'/'.$dirsource;
999  $dirdest = $fileentry['path'].'/'.$dirdest;
1000  @rename($dirsource, $dirdest);
1001  }
1002  }
1003  }
1004  }
1005  }
1006 
1007  // Set new ref and current status
1008  if (!$error) {
1009  $this->ref = $num;
1010  $this->status = self::STATUS_VALIDATED;
1011  }
1012 
1013  if (!$error) {
1014  $this->db->commit();
1015  return 1;
1016  } else {
1017  $this->db->rollback();
1018  return -1;
1019  }
1020  }
1021 
1029  public function setDraft($user, $notrigger = 0)
1030  {
1031  // Protection
1032  if ($this->status <= self::STATUS_DRAFT) {
1033  return 0;
1034  }
1035 
1036  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1037  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1038  {
1039  $this->error='Permission denied';
1040  return -1;
1041  }*/
1042 
1043  return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'BOM_UNVALIDATE');
1044  }
1045 
1053  public function cancel($user, $notrigger = 0)
1054  {
1055  // Protection
1056  if ($this->status != self::STATUS_VALIDATED) {
1057  return 0;
1058  }
1059 
1060  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1061  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1062  {
1063  $this->error='Permission denied';
1064  return -1;
1065  }*/
1066 
1067  return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'BOM_CLOSE');
1068  }
1069 
1077  public function reopen($user, $notrigger = 0)
1078  {
1079  // Protection
1080  if ($this->status != self::STATUS_CANCELED) {
1081  return 0;
1082  }
1083 
1084  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->write))
1085  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->bom->bom_advance->validate))))
1086  {
1087  $this->error='Permission denied';
1088  return -1;
1089  }*/
1090 
1091  return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'BOM_REOPEN');
1092  }
1093 
1100  public function getTooltipContentArray($params)
1101  {
1102  global $conf, $langs, $user;
1103 
1104  $langs->loadLangs(['product', 'mrp']);
1105 
1106  $datas = [];
1107 
1108  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1109  return ['optimize' => $langs->trans("ShowBillOfMaterials")];
1110  }
1111  $picto = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("BillOfMaterials").'</u>';
1112  if (isset($this->status)) {
1113  $picto .= ' '.$this->getLibStatut(5);
1114  }
1115  $datas['picto'] = $picto;
1116  $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1117  if (isset($this->label)) {
1118  $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1119  }
1120  if (!empty($this->fk_product) && $this->fk_product > 0) {
1121  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1122  $product = new Product($this->db);
1123  $resultFetch = $product->fetch($this->fk_product);
1124  if ($resultFetch > 0) {
1125  $datas['product'] = "<br><b>".$langs->trans("Product").'</b>: '.$product->ref.' - '.$product->label;
1126  }
1127  }
1128 
1129  return $datas;
1130  }
1131 
1142  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1143  {
1144  global $db, $conf, $langs, $hookmanager;
1145 
1146  if (!empty($conf->dol_no_mouse_hover)) {
1147  $notooltip = 1; // Force disable tooltips
1148  }
1149 
1150  $result = '';
1151  $params = [
1152  'id' => $this->id,
1153  'objecttype' => $this->element,
1154  'option' => $option,
1155  ];
1156  $classfortooltip = 'classfortooltip';
1157  $dataparams = '';
1158  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1159  $classfortooltip = 'classforajaxtooltip';
1160  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1161  $label = '';
1162  } else {
1163  $label = implode($this->getTooltipContentArray($params));
1164  }
1165 
1166  $url = DOL_URL_ROOT.'/bom/bom_card.php?id='.$this->id;
1167 
1168  if ($option != 'nolink') {
1169  // Add param to save lastsearch_values or not
1170  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1171  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1172  $add_save_lastsearch_values = 1;
1173  }
1174  if ($add_save_lastsearch_values) {
1175  $url .= '&save_lastsearch_values=1';
1176  }
1177  }
1178 
1179  $linkclose = '';
1180  if (empty($notooltip)) {
1181  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1182  $label = $langs->trans("ShowBillOfMaterials");
1183  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1184  }
1185  $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1186  $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1187  } else {
1188  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1189  }
1190 
1191  $linkstart = '<a href="'.$url.'"';
1192  $linkstart .= $linkclose.'>';
1193  $linkend = '</a>';
1194 
1195  $result .= $linkstart;
1196  if ($withpicto) {
1197  $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
1198  }
1199  if ($withpicto != 2) {
1200  $result .= $this->ref;
1201  }
1202  $result .= $linkend;
1203  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1204 
1205  global $action, $hookmanager;
1206  $hookmanager->initHooks(array('bomdao'));
1207  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1208  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1209  if ($reshook > 0) {
1210  $result = $hookmanager->resPrint;
1211  } else {
1212  $result .= $hookmanager->resPrint;
1213  }
1214 
1215  return $result;
1216  }
1217 
1224  public function getLibStatut($mode = 0)
1225  {
1226  return $this->LibStatut($this->status, $mode);
1227  }
1228 
1229  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1237  public function LibStatut($status, $mode = 0)
1238  {
1239  // phpcs:enable
1240  if (empty($this->labelStatus)) {
1241  global $langs;
1242  //$langs->load("mrp");
1243  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1244  $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
1245  $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
1246  }
1247 
1248  $statusType = 'status'.$status;
1249  if ($status == self::STATUS_VALIDATED) {
1250  $statusType = 'status4';
1251  }
1252  if ($status == self::STATUS_CANCELED) {
1253  $statusType = 'status6';
1254  }
1255 
1256  return dolGetStatus($this->labelStatus[$status], $this->labelStatus[$status], '', $statusType, $mode);
1257  }
1258 
1265  public function info($id)
1266  {
1267  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1268  $sql .= ' fk_user_creat, fk_user_modif';
1269  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1270  $sql .= ' WHERE t.rowid = '.((int) $id);
1271  $result = $this->db->query($sql);
1272  if ($result) {
1273  if ($this->db->num_rows($result)) {
1274  $obj = $this->db->fetch_object($result);
1275  $this->id = $obj->rowid;
1276 
1277  $this->user_creation_id = $obj->fk_user_creat;
1278  $this->user_modification_id = $obj->fk_user_modif;
1279  $this->date_creation = $this->db->jdate($obj->datec);
1280  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1281  }
1282 
1283  $this->db->free($result);
1284  } else {
1285  dol_print_error($this->db);
1286  }
1287  }
1288 
1294  public function getLinesArray()
1295  {
1296  $this->lines = array();
1297 
1298  $objectline = new BOMLine($this->db);
1299  $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_bom = '.((int) $this->id)));
1300 
1301  if (is_numeric($result)) {
1302  $this->error = $objectline->error;
1303  $this->errors = $objectline->errors;
1304  return $result;
1305  } else {
1306  $this->lines = $result;
1307  return $this->lines;
1308  }
1309  }
1310 
1322  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1323  {
1324  global $conf, $langs;
1325 
1326  $langs->load("mrp");
1327  $outputlangs->load("products");
1328 
1329  if (!dol_strlen($modele)) {
1330  $modele = '';
1331 
1332  if ($this->model_pdf) {
1333  $modele = $this->model_pdf;
1334  } elseif (!empty($conf->global->BOM_ADDON_PDF)) {
1335  $modele = $conf->global->BOM_ADDON_PDF;
1336  }
1337  }
1338 
1339  $modelpath = "core/modules/bom/doc/";
1340  if (!empty($modele)) {
1341  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1342  } else {
1343  return 0;
1344  }
1345  }
1346 
1353  public function initAsSpecimen()
1354  {
1355  $this->initAsSpecimenCommon();
1356  $this->ref = 'BOM-123';
1357  $this->date = $this->date_creation;
1358  }
1359 
1360 
1367  public function doScheduledJob()
1368  {
1369  global $conf, $langs;
1370 
1371  //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1372 
1373  $error = 0;
1374  $this->output = '';
1375  $this->error = '';
1376 
1377  dol_syslog(__METHOD__, LOG_DEBUG);
1378 
1379  $now = dol_now();
1380 
1381  $this->db->begin();
1382 
1383  // ...
1384 
1385  $this->db->commit();
1386 
1387  return $error;
1388  }
1389 
1396  public function calculateCosts()
1397  {
1398  global $conf, $hookmanager;
1399 
1400  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1401  $this->unit_cost = 0;
1402  $this->total_cost = 0;
1403 
1404  $parameters=array();
1405  $reshook = $hookmanager->executeHooks('calculateCostsBom', $parameters, $this); // Note that $action and $object may have been modified by hook
1406 
1407  if ($reshook > 0) {
1408  return $hookmanager->resPrint;
1409  }
1410 
1411  if (is_array($this->lines) && count($this->lines)) {
1412  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1413  $productFournisseur = new ProductFournisseur($this->db);
1414  $tmpproduct = new Product($this->db);
1415 
1416  foreach ($this->lines as &$line) {
1417  $tmpproduct->cost_price = 0;
1418  $tmpproduct->pmp = 0;
1419  $result = $tmpproduct->fetch($line->fk_product, '', '', '', 0, 1, 1); // We discard selling price and language loading
1420 
1421  if ($tmpproduct->type == $tmpproduct::TYPE_PRODUCT) {
1422  if (empty($line->fk_bom_child)) {
1423  if ($result < 0) {
1424  $this->error = $tmpproduct->error;
1425  return -1;
1426  }
1427  $line->unit_cost = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
1428  if (empty($line->unit_cost)) {
1429  if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0) {
1430  if ($productFournisseur->fourn_remise_percent != "0") {
1431  $line->unit_cost = $productFournisseur->fourn_unitprice_with_discount;
1432  } else {
1433  $line->unit_cost = $productFournisseur->fourn_unitprice;
1434  }
1435  }
1436  }
1437 
1438  $line->total_cost = price2num($line->qty * $line->unit_cost, 'MT');
1439 
1440  $this->total_cost += $line->total_cost;
1441  } else {
1442  $bom_child = new BOM($this->db);
1443  $res = $bom_child->fetch($line->fk_bom_child);
1444  if ($res > 0) {
1445  $bom_child->calculateCosts();
1446  $line->childBom[] = $bom_child;
1447  $this->total_cost += price2num($bom_child->total_cost * $line->qty, 'MT');
1448  $this->total_cost += $line->total_cost;
1449  } else {
1450  $this->error = $bom_child->error;
1451  return -2;
1452  }
1453  }
1454  } else {
1455  // Convert qty of line into hours
1456  $unitforline = measuringUnitString($line->fk_unit, '', '', 1);
1457  $qtyhourforline = convertDurationtoHour($line->qty, $unitforline);
1458 
1459  if (isModEnabled('workstation') && !empty($tmpproduct->fk_default_workstation)) {
1460  $workstation = new Workstation($this->db);
1461  $res = $workstation->fetch($tmpproduct->fk_default_workstation);
1462 
1463  if ($res > 0) $line->total_cost = price2num($qtyhourforline * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated), 'MT');
1464  else {
1465  $this->error = $workstation->error;
1466  return -3;
1467  }
1468  } else {
1469  $defaultdurationofservice = $tmpproduct->duration;
1470  $reg = array();
1471  $qtyhourservice = 0;
1472  if (preg_match('/^(\d+)([a-z]+)$/', $defaultdurationofservice, $reg)) {
1473  $qtyhourservice = convertDurationtoHour($reg[1], $reg[2]);
1474  }
1475 
1476  if ($qtyhourservice) {
1477  $line->total_cost = price2num($qtyhourforline / $qtyhourservice * $tmpproduct->cost_price, 'MT');
1478  } else {
1479  $line->total_cost = price2num($line->qty * $tmpproduct->cost_price, 'MT');
1480  }
1481  }
1482 
1483  $this->total_cost += $line->total_cost;
1484  }
1485  }
1486 
1487  $this->total_cost = price2num($this->total_cost, 'MT');
1488 
1489  if ($this->qty > 0) {
1490  $this->unit_cost = price2num($this->total_cost / $this->qty, 'MU');
1491  } elseif ($this->qty < 0) {
1492  $this->unit_cost = price2num($this->total_cost * $this->qty, 'MU');
1493  }
1494  }
1495 
1496  return 1;
1497  }
1498 
1507  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1508  {
1509  $tables = array(
1510  'bom_bomline'
1511  );
1512 
1513  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1514  }
1515 
1523  public function getNetNeeds(&$TNetNeeds = array(), $qty = 0)
1524  {
1525  if (!empty($this->lines)) {
1526  foreach ($this->lines as $line) {
1527  if (!empty($line->childBom)) {
1528  foreach ($line->childBom as $childBom) $childBom->getNetNeeds($TNetNeeds, $line->qty*$qty);
1529  } else {
1530  if (empty($TNetNeeds[$line->fk_product])) {
1531  $TNetNeeds[$line->fk_product] = 0;
1532  }
1533  $TNetNeeds[$line->fk_product] += $line->qty*$qty;
1534  }
1535  }
1536  }
1537  }
1538 
1547  public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0)
1548  {
1549  if (!empty($this->lines)) {
1550  foreach ($this->lines as $line) {
1551  if (!empty($line->childBom)) {
1552  foreach ($line->childBom as $childBom) {
1553  $TNetNeeds[$childBom->id]['bom'] = $childBom;
1554  $TNetNeeds[$childBom->id]['parentid'] = $this->id;
1555  $TNetNeeds[$childBom->id]['qty'] = $line->qty*$qty;
1556  $TNetNeeds[$childBom->id]['level'] = $level;
1557  $childBom->getNetNeedsTree($TNetNeeds, $line->qty*$qty, $level+1);
1558  }
1559  } else {
1560  $TNetNeeds[$this->id]['product'][$line->fk_product]['qty'] += $line->qty * $qty;
1561  $TNetNeeds[$this->id]['product'][$line->fk_product]['level'] = $level;
1562  }
1563  }
1564  }
1565  }
1566 
1575  public function getParentBomTreeRecursive(&$TParentBom, $bom_id = '', $level = 1)
1576  {
1577 
1578  // Protection against infinite loop
1579  if ($level > 1000) {
1580  return;
1581  }
1582 
1583  if (empty($bom_id)) $bom_id=$this->id;
1584 
1585  $sql = 'SELECT l.fk_bom, b.label
1586  FROM '.MAIN_DB_PREFIX.'bom_bomline l
1587  INNER JOIN '.MAIN_DB_PREFIX.$this->table_element.' b ON b.rowid = l.fk_bom
1588  WHERE fk_bom_child = '.((int) $bom_id);
1589 
1590  $resql = $this->db->query($sql);
1591  if (!empty($resql)) {
1592  while ($res = $this->db->fetch_object($resql)) {
1593  $TParentBom[$res->fk_bom] = $res->fk_bom;
1594  $this->getParentBomTreeRecursive($TParentBom, $res->fk_bom, $level+1);
1595  }
1596  }
1597  }
1598 
1606  public function getKanbanView($option = '', $arraydata = null)
1607  {
1608  global $db,$langs;
1609 
1610  $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1611 
1612  $prod = new Product($db);
1613  $prod->fetch($this->fk_product);
1614 
1615  $return = '<div class="box-flex-item box-flex-grow-zero">';
1616  $return .= '<div class="info-box info-box-sm">';
1617  $return .= '<span class="info-box-icon bg-infobox-action">';
1618  $return .= img_picto('', $this->picto);
1619  $return .= '</span>';
1620  $return .= '<div class="info-box-content">';
1621  $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : '').'</span>';
1622  $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1623  if (property_exists($this, 'fields') && !empty($this->fields['bomtype']['arrayofkeyval'])) {
1624  $return .= '<br><span class="info-box-label opacitymedium">'.$langs->trans("Type").' : </span>';
1625  if ($this->bomtype == 0) {
1626  $return .= '<span class="info-box-label">'.$this->fields['bomtype']['arrayofkeyval'][0].'</span>';
1627  } else {
1628  $return .= '<span class="info-box-label">'.$this->fields['bomtype']['arrayofkeyval'][1].'</span>';
1629  }
1630  }
1631  if (property_exists($this, 'fk_product') && !is_null($this->fk_product)) {
1632  $return .= '<br><span class="info-box-label">'.$prod->getNomUrl(1).'</span>';
1633  }
1634  if (method_exists($this, 'getLibStatut')) {
1635  $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3).'</div>';
1636  }
1637 
1638  $return .= '</div>';
1639  $return .= '</div>';
1640  $return .= '</div>';
1641  return $return;
1642  }
1643 }
1644 
1645 
1650 {
1654  public $element = 'bomline';
1655 
1659  public $table_element = 'bom_bomline';
1660 
1664  public $ismultientitymanaged = 0;
1665 
1669  public $isextrafieldmanaged = 1;
1670 
1674  public $picto = 'bomline';
1675 
1676 
1696  // BEGIN MODULEBUILDER PROPERTIES
1700  public $fields = array(
1701  'rowid' => array('type'=>'integer', 'label'=>'LineID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
1702  'fk_bom' => array('type'=>'integer:BillOfMaterials:societe/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1,),
1703  'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
1704  'fk_bom_child' => array('type'=>'integer:BOM:bom/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>-1, 'position'=>40, 'notnull'=>-1,),
1705  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
1706  'qty' => array('type'=>'double(24,8)', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'position'=>100, 'notnull'=>1, 'isameasure'=>'1',),
1707  'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
1708  'disable_stock_change' => array('type'=>'smallint', 'label'=>'DisableStockChange', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>108, 'css'=>'maxwidth50imp', 'help'=>'DisableStockChangeHelp'),
1709  'efficiency' => array('type'=>'double(24,8)', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'position'=>110, 'notnull'=>1, 'css'=>'maxwidth50imp', 'help'=>'ValueOfEfficiencyConsumedMeans'),
1710  'fk_unit' => array('type'=>'integer', 'label'=>'Unit', 'enabled'=>1, 'visible'=>1, 'position'=>120, 'notnull'=>-1,),
1711  'position' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>1, 'visible'=>0, 'default'=>0, 'position'=>200, 'notnull'=>1,),
1712  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
1713  'fk_default_workstation' =>array('type'=>'integer', 'label'=>'DefaultWorkstation', 'enabled'=>1, 'visible'=>1, 'notnull'=>0, 'position'=>1050)
1714  );
1715 
1719  public $rowid;
1720 
1724  public $fk_bom;
1725 
1729  public $fk_product;
1730 
1734  public $fk_bom_child;
1735 
1739  public $description;
1740  public $qty;
1741 
1745  public $qty_frozen;
1746  public $disable_stock_change;
1747  public $efficiency;
1748 
1752  public $position;
1753 
1757  public $import_key;
1758  // END MODULEBUILDER PROPERTIES
1759 
1763  public $total_cost = 0;
1764 
1768  public $unit_cost = 0;
1769 
1770 
1774  public $childBom = array();
1775 
1779  public $fk_default_workstation;
1780 
1781 
1782 
1788  public function __construct(DoliDB $db)
1789  {
1790  global $conf, $langs;
1791 
1792  $this->db = $db;
1793 
1794  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
1795  $this->fields['rowid']['visible'] = 0;
1796  }
1797  if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
1798  $this->fields['entity']['enabled'] = 0;
1799  }
1800 
1801  // Unset fields that are disabled
1802  foreach ($this->fields as $key => $val) {
1803  if (isset($val['enabled']) && empty($val['enabled'])) {
1804  unset($this->fields[$key]);
1805  }
1806  }
1807 
1808  // Translate some data of arrayofkeyval
1809  foreach ($this->fields as $key => $val) {
1810  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
1811  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
1812  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
1813  }
1814  }
1815  }
1816  }
1817 
1825  public function create(User $user, $notrigger = false)
1826  {
1827  if ($this->efficiency < 0 || $this->efficiency > 1) {
1828  $this->efficiency = 1;
1829  }
1830 
1831  return $this->createCommon($user, $notrigger);
1832  }
1833 
1841  public function fetch($id, $ref = null)
1842  {
1843  $result = $this->fetchCommon($id, $ref);
1844  //if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
1845  return $result;
1846  }
1847 
1859  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
1860  {
1861  global $conf;
1862 
1863  dol_syslog(__METHOD__, LOG_DEBUG);
1864 
1865  $records = array();
1866 
1867  $sql = 'SELECT ';
1868  $sql .= $this->getFieldList();
1869  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1870  if ($this->ismultientitymanaged) {
1871  $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
1872  } else {
1873  $sql .= ' WHERE 1 = 1';
1874  }
1875  // Manage filter
1876  $sqlwhere = array();
1877  if (count($filter) > 0) {
1878  foreach ($filter as $key => $value) {
1879  if ($key == 't.rowid') {
1880  $sqlwhere[] = $key." = ".((int) $value);
1881  } elseif (strpos($key, 'date') !== false) {
1882  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
1883  } elseif ($key == 'customsql') {
1884  $sqlwhere[] = $value;
1885  } else {
1886  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
1887  }
1888  }
1889  }
1890  if (count($sqlwhere) > 0) {
1891  $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
1892  }
1893 
1894  if (!empty($sortfield)) {
1895  $sql .= $this->db->order($sortfield, $sortorder);
1896  }
1897  if (!empty($limit)) {
1898  $sql .= $this->db->plimit($limit, $offset);
1899  }
1900 
1901  $resql = $this->db->query($sql);
1902  if ($resql) {
1903  $num = $this->db->num_rows($resql);
1904 
1905  while ($obj = $this->db->fetch_object($resql)) {
1906  $record = new self($this->db);
1907  $record->setVarsFromFetchObj($obj);
1908 
1909  $records[$record->id] = $record;
1910  }
1911  $this->db->free($resql);
1912 
1913  return $records;
1914  } else {
1915  $this->errors[] = 'Error '.$this->db->lasterror();
1916  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1917 
1918  return -1;
1919  }
1920  }
1921 
1929  public function update(User $user, $notrigger = false)
1930  {
1931  if ($this->efficiency < 0 || $this->efficiency > 1) {
1932  $this->efficiency = 1;
1933  }
1934 
1935  return $this->updateCommon($user, $notrigger);
1936  }
1937 
1945  public function delete(User $user, $notrigger = false)
1946  {
1947  return $this->deleteCommon($user, $notrigger);
1948  //return $this->deleteCommon($user, $notrigger, 1);
1949  }
1950 
1961  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1962  {
1963  global $db, $conf, $langs, $hookmanager;
1964 
1965  if (!empty($conf->dol_no_mouse_hover)) {
1966  $notooltip = 1; // Force disable tooltips
1967  }
1968 
1969  $result = '';
1970 
1971  $label = '<u>'.$langs->trans("BillOfMaterialsLine").'</u>';
1972  $label .= '<br>';
1973  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1974 
1975  $url = DOL_URL_ROOT.'/bom/bomline_card.php?id='.$this->id;
1976 
1977  if ($option != 'nolink') {
1978  // Add param to save lastsearch_values or not
1979  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1980  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1981  $add_save_lastsearch_values = 1;
1982  }
1983  if ($add_save_lastsearch_values) {
1984  $url .= '&save_lastsearch_values=1';
1985  }
1986  }
1987 
1988  $linkclose = '';
1989  if (empty($notooltip)) {
1990  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1991  $label = $langs->trans("ShowBillOfMaterialsLine");
1992  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1993  }
1994  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1995  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1996  } else {
1997  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1998  }
1999 
2000  $linkstart = '<a href="'.$url.'"';
2001  $linkstart .= $linkclose.'>';
2002  $linkend = '</a>';
2003 
2004  $result .= $linkstart;
2005  if ($withpicto) {
2006  $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);
2007  }
2008  if ($withpicto != 2) {
2009  $result .= $this->ref;
2010  }
2011  $result .= $linkend;
2012  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
2013 
2014  global $action, $hookmanager;
2015  $hookmanager->initHooks(array('bomlinedao'));
2016  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
2017  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2018  if ($reshook > 0) {
2019  $result = $hookmanager->resPrint;
2020  } else {
2021  $result .= $hookmanager->resPrint;
2022  }
2023 
2024  return $result;
2025  }
2026 
2033  public function getLibStatut($mode = 0)
2034  {
2035  return $this->LibStatut($this->status, $mode);
2036  }
2037 
2038  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2046  public function LibStatut($status, $mode = 0)
2047  {
2048  // phpcs:enable
2049  return '';
2050  }
2051 
2058  public function info($id)
2059  {
2060  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
2061  $sql .= ' fk_user_creat, fk_user_modif';
2062  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
2063  $sql .= ' WHERE t.rowid = '.((int) $id);
2064  $result = $this->db->query($sql);
2065  if ($result) {
2066  if ($this->db->num_rows($result)) {
2067  $obj = $this->db->fetch_object($result);
2068  $this->id = $obj->rowid;
2069  $this->user_creation_id = $obj->fk_user_creat;
2070  $this->user_modification_id = $obj->fk_user_modif;
2071  $this->date_creation = $this->db->jdate($obj->datec);
2072  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
2073  }
2074  $this->db->free($result);
2075  } else {
2076  dol_print_error($this->db);
2077  }
2078  }
2079 
2086  public function initAsSpecimen()
2087  {
2088  $this->initAsSpecimenCommon();
2089  }
2090 }
CommonObject\deleteCommon
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
Definition: commonobject.class.php:9605
CommonObject\setStatusCommon
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
Definition: commonobject.class.php:9883
CommonObject\fetchCommon
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9395
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:709
CommonObject\copy_linked_contact
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
Definition: commonobject.class.php:1132
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:1859
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:438
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:743
BOMLine\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:2033
BOMLine
Class for BOMLine.
Definition: bom.class.php:1649
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:299
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:9451
BOM\calculateCosts
calculateCosts()
BOM costs calculation based on cost_price or pmp of each BOM line.
Definition: bom.class.php:1396
BOM\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:1224
BOM\getNetNeedsTree
getNetNeedsTree(&$TNetNeeds=array(), $qty=0, $level=0)
Get Net needs Tree by product or bom.
Definition: bom.class.php:1547
CommonObject\initAsSpecimenCommon
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: commonobject.class.php:9933
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:1788
BOM
Class for BOM.
Definition: bom.class.php:42
BOM\getNextNumRef
getNextNumRef($prod)
Returns the reference to the following non used BOM depending on the active numbering module defined ...
Definition: bom.class.php:862
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:2046
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:1507
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:602
BOMLine\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:2086
BOM\cancel
cancel($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:1053
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:5381
CommonObject\createCommon
createCommon(User $user, $notrigger=false)
Create object into database.
Definition: commonobject.class.php:9228
BOM\createFromClone
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition: bom.class.php:315
BOM\reopen
reopen($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:1077
BOMLine\create
create(User $user, $notrigger=false)
Create object into database.
Definition: bom.class.php:1825
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:1961
BOMLine\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bom.class.php:1929
BOMLine\info
info($id)
Load the info information in the object.
Definition: bom.class.php:2058
BOM\deleteLine
deleteLine(User $user, $idline, $notrigger=false)
Delete a line of object in database.
Definition: bom.class.php:815
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:1575
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:8553
BOM\getLinesArray
getLinesArray()
Create an array of lines.
Definition: bom.class.php:1294
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:1523
BOM\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:406
BOM\__construct
__construct(DoliDB $db)
Constructor.
Definition: bom.class.php:262
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3337
BOM\validate
validate($user, $notrigger=0)
Validate bom.
Definition: bom.class.php:910
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:494
CommonObject\updateCommon
updateCommon(User $user, $notrigger=false)
Update object into database.
Definition: commonobject.class.php:9501
BOM\doScheduledJob
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
Definition: bom.class.php:1367
BOM\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: bom.class.php:1100
$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:1801
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:564
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:1237
BOM\setDraft
setDraft($user, $notrigger=0)
Set draft status.
Definition: bom.class.php:1029
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:423
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:1142
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:1265
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5790
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:1322
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:9180
BOM\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:1353
BOMLine\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:1841
BOM\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: bom.class.php:1606