dolibarr  16.0.5
bom.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2019 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2023 Benjamin Falière <benjamin.faliere@altairis.fr>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
25 // Put here all includes required by your class file
26 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
27 //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
28 //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
29 
30 
34 class BOM extends CommonObject
35 {
39  public $element = 'bom';
40 
44  public $table_element = 'bom_bom';
45 
49  public $ismultientitymanaged = 1;
50 
54  public $isextrafieldmanaged = 1;
55 
59  public $picto = 'bom';
60 
61 
62  const STATUS_DRAFT = 0;
63  const STATUS_VALIDATED = 1;
64  const STATUS_CANCELED = 9;
65 
66 
93  // BEGIN MODULEBUILDER PROPERTIES
97  public $fields = array(
98  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
99  'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=> 1, 'default'=>1, 'index'=>1, 'position'=>5),
100  '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'),
101  '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'),
102  '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'),
103  //'bomtype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'position'=>32, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing')),
104  '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'),
105  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
106  'qty' => array('type'=>'real', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'position'=>55, 'notnull'=>1, 'isameasure'=>'1', 'css'=>'maxwidth75imp'),
107  //'efficiency' => array('type'=>'real', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>-1, 'default'=>1, 'position'=>100, 'notnull'=>0, 'css'=>'maxwidth50imp', 'help'=>'ValueOfMeansLossForProductProduced'),
108  'duration' => array('type'=>'duration', 'label'=>'EstimatedDuration', 'enabled'=>1, 'visible'=>-1, 'position'=>101, 'notnull'=>-1, 'css'=>'maxwidth50imp', 'help'=>'EstimatedDurationDesc'),
109  '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'),
110  'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>-2, 'position'=>161, 'notnull'=>-1,),
111  'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>-2, 'position'=>162, 'notnull'=>-1,),
112  'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>300, 'notnull'=>1,),
113  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,),
114  'date_valid' => array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>502, 'notnull'=>0,),
115  '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'),
116  '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'),
117  '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'),
118  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
119  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
120  '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')),
121  );
122 
126  public $rowid;
127 
131  public $ref;
132 
136  public $label;
137 
141  public $bomtype;
142 
146  public $description;
147 
151  public $date_creation;
152 
153 
154  public $tms;
155 
159  public $fk_user_creat;
160 
164  public $fk_user_modif;
165 
169  public $import_key;
170 
174  public $status;
175 
179  public $fk_product;
180  public $qty;
181  public $efficiency;
182  // END MODULEBUILDER PROPERTIES
183 
184 
185  // If this object has a subtable with lines
186 
190  public $table_element_line = 'bom_bomline';
191 
195  public $fk_element = 'fk_bom';
196 
200  public $class_element_line = 'BOMLine';
201 
202  // /**
203  // * @var array List of child tables. To test if we can delete object.
204  // */
205  // protected $childtables=array();
206 
210  protected $childtablesoncascade = array('bom_bomline');
211 
215  public $lines = array();
216 
220  public $total_cost = 0;
221 
225  public $unit_cost = 0;
226 
227 
228 
234  public function __construct(DoliDB $db)
235  {
236  global $conf, $langs;
237 
238  $this->db = $db;
239 
240  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
241  $this->fields['rowid']['visible'] = 0;
242  }
243  if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) {
244  $this->fields['entity']['enabled'] = 0;
245  }
246 
247  // Unset fields that are disabled
248  foreach ($this->fields as $key => $val) {
249  if (isset($val['enabled']) && empty($val['enabled'])) {
250  unset($this->fields[$key]);
251  }
252  }
253 
254  // Translate some data of arrayofkeyval
255  foreach ($this->fields as $key => $val) {
256  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
257  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
258  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
259  }
260  }
261  }
262  }
263 
271  public function create(User $user, $notrigger = false)
272  {
273  if ($this->efficiency <= 0 || $this->efficiency > 1) {
274  $this->efficiency = 1;
275  }
276 
277  return $this->createCommon($user, $notrigger);
278  }
279 
287  public function createFromClone(User $user, $fromid)
288  {
289  global $langs, $hookmanager, $extrafields;
290  $error = 0;
291 
292  dol_syslog(__METHOD__, LOG_DEBUG);
293 
294  $object = new self($this->db);
295 
296  $this->db->begin();
297 
298  // Load source object
299  $result = $object->fetchCommon($fromid);
300  if ($result > 0 && !empty($object->table_element_line)) {
301  $object->fetchLines();
302  }
303 
304  // Get lines so they will be clone
305  //foreach ($object->lines as $line)
306  // $line->fetch_optionals();
307 
308  // Reset some properties
309  unset($object->id);
310  unset($object->fk_user_creat);
311  unset($object->import_key);
312 
313  // Clear fields
314  $object->ref = empty($this->fields['ref']['default']) ? $langs->trans("copy_of_").$object->ref : $this->fields['ref']['default'];
315  $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
316  $object->status = self::STATUS_DRAFT;
317  // ...
318  // Clear extrafields that are unique
319  if (is_array($object->array_options) && count($object->array_options) > 0) {
320  $extrafields->fetch_name_optionals_label($object->table_element);
321  foreach ($object->array_options as $key => $option) {
322  $shortkey = preg_replace('/options_/', '', $key);
323  if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
324  //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
325  unset($object->array_options[$key]);
326  }
327  }
328  }
329 
330  // Create clone
331  $object->context['createfromclone'] = 'createfromclone';
332  $result = $object->createCommon($user);
333  if ($result < 0) {
334  $error++;
335  $this->error = $object->error;
336  $this->errors = $object->errors;
337  }
338 
339  if (!$error) {
340  // copy internal contacts
341  if ($this->copy_linked_contact($object, 'internal') < 0) {
342  $error++;
343  }
344  }
345 
346  if (!$error) {
347  // copy external contacts if same company
348  if (property_exists($this, 'socid') && $this->socid == $object->socid) {
349  if ($this->copy_linked_contact($object, 'external') < 0) {
350  $error++;
351  }
352  }
353  }
354 
355  // If there is lines, create lines too
356 
357 
358 
359  unset($object->context['createfromclone']);
360 
361  // End
362  if (!$error) {
363  $this->db->commit();
364  return $object;
365  } else {
366  $this->db->rollback();
367  return -1;
368  }
369  }
370 
378  public function fetch($id, $ref = null)
379  {
380  $result = $this->fetchCommon($id, $ref);
381 
382  if ($result > 0 && !empty($this->table_element_line)) {
383  $this->fetchLines();
384  }
385  //$this->calculateCosts(); // This consume a high number of subrequests. Do not call it into fetch but when you need it.
386 
387  return $result;
388  }
389 
395  public function fetchLines()
396  {
397  $this->lines = array();
398 
399  $result = $this->fetchLinesCommon();
400  return $result;
401  }
402 
414  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
415  {
416  global $conf;
417 
418  dol_syslog(__METHOD__, LOG_DEBUG);
419 
420  $records = array();
421 
422  $sql = 'SELECT ';
423  $sql .= $this->getFieldList();
424  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
425  if ($this->ismultientitymanaged) {
426  $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')';
427  } else {
428  $sql .= ' WHERE 1 = 1';
429  }
430  // Manage filter
431  $sqlwhere = array();
432  if (count($filter) > 0) {
433  foreach ($filter as $key => $value) {
434  if ($key == 't.rowid') {
435  $sqlwhere[] = $key." = ".((int) $value);
436  } elseif (strpos($key, 'date') !== false) {
437  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
438  } elseif ($key == 'customsql') {
439  $sqlwhere[] = $value;
440  } else {
441  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
442  }
443  }
444  }
445  if (count($sqlwhere) > 0) {
446  $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
447  }
448 
449  if (!empty($sortfield)) {
450  $sql .= $this->db->order($sortfield, $sortorder);
451  }
452  if (!empty($limit)) {
453  $sql .= $this->db->plimit($limit, $offset);
454  }
455 
456  $resql = $this->db->query($sql);
457  if ($resql) {
458  $num = $this->db->num_rows($resql);
459 
460  while ($obj = $this->db->fetch_object($resql)) {
461  $record = new self($this->db);
462  $record->setVarsFromFetchObj($obj);
463 
464  $records[$record->id] = $record;
465  }
466  $this->db->free($resql);
467 
468  return $records;
469  } else {
470  $this->errors[] = 'Error '.$this->db->lasterror();
471  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
472 
473  return -1;
474  }
475  }
476 
484  public function update(User $user, $notrigger = false)
485  {
486  if ($this->efficiency <= 0 || $this->efficiency > 1) {
487  $this->efficiency = 1;
488  }
489 
490  return $this->updateCommon($user, $notrigger);
491  }
492 
500  public function delete(User $user, $notrigger = false)
501  {
502  return $this->deleteCommon($user, $notrigger);
503  //return $this->deleteCommon($user, $notrigger, 1);
504  }
505 
514  public function deleteLine(User $user, $idline, $notrigger = false)
515  {
516  if ($this->status < 0) {
517  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
518  return -2;
519  }
520 
521  return $this->deleteLineCommon($user, $idline, $notrigger);
522  }
523 
531  public function getNextNumRef($prod)
532  {
533  global $langs, $conf;
534  $langs->load("mrp");
535 
536  if (!empty($conf->global->BOM_ADDON)) {
537  $mybool = false;
538 
539  $file = $conf->global->BOM_ADDON.".php";
540  $classname = $conf->global->BOM_ADDON;
541 
542  // Include file with class
543  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
544  foreach ($dirmodels as $reldir) {
545  $dir = dol_buildpath($reldir."core/modules/bom/");
546 
547  // Load file with numbering class (if found)
548  $mybool |= @include_once $dir.$file;
549  }
550 
551  if ($mybool === false) {
552  dol_print_error('', "Failed to include file ".$file);
553  return '';
554  }
555 
556  $obj = new $classname();
557  $numref = $obj->getNextValue($prod, $this);
558 
559  if ($numref != "") {
560  return $numref;
561  } else {
562  $this->error = $obj->error;
563  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
564  return "";
565  }
566  } else {
567  print $langs->trans("Error")." ".$langs->trans("Error_BOM_ADDON_NotDefined");
568  return "";
569  }
570  }
571 
579  public function validate($user, $notrigger = 0)
580  {
581  global $conf, $langs;
582 
583  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
584 
585  $error = 0;
586 
587  // Protection
588  if ($this->status == self::STATUS_VALIDATED) {
589  dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
590  return 0;
591  }
592 
593  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->create))
594  || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->bom_advance->validate))))
595  {
596  $this->error='NotEnoughPermissions';
597  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
598  return -1;
599  }*/
600 
601  $now = dol_now();
602 
603  $this->db->begin();
604 
605  // Define new ref
606  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
607  $this->fetch_product();
608  $num = $this->getNextNumRef($this->product);
609  } else {
610  $num = $this->ref;
611  }
612  $this->newref = dol_sanitizeFileName($num);
613 
614  // Validate
615  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
616  $sql .= " SET ref = '".$this->db->escape($num)."',";
617  $sql .= " status = ".self::STATUS_VALIDATED.",";
618  $sql .= " date_valid='".$this->db->idate($now)."',";
619  $sql .= " fk_user_valid = ".((int) $user->id);
620  $sql .= " WHERE rowid = ".((int) $this->id);
621 
622  dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
623  $resql = $this->db->query($sql);
624  if (!$resql) {
625  dol_print_error($this->db);
626  $this->error = $this->db->lasterror();
627  $error++;
628  }
629 
630  if (!$error && !$notrigger) {
631  // Call trigger
632  $result = $this->call_trigger('BOM_VALIDATE', $user);
633  if ($result < 0) {
634  $error++;
635  }
636  // End call triggers
637  }
638 
639  if (!$error) {
640  $this->oldref = $this->ref;
641 
642  // Rename directory if dir was a temporary ref
643  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
644  // Now we rename also files into index
645  $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)."'";
646  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'bom/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
647  $resql = $this->db->query($sql);
648  if (!$resql) {
649  $error++; $this->error = $this->db->lasterror();
650  }
651 
652  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
653  $oldref = dol_sanitizeFileName($this->ref);
654  $newref = dol_sanitizeFileName($num);
655  $dirsource = $conf->bom->dir_output.'/'.$oldref;
656  $dirdest = $conf->bom->dir_output.'/'.$newref;
657  if (!$error && file_exists($dirsource)) {
658  dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
659 
660  if (@rename($dirsource, $dirdest)) {
661  dol_syslog("Rename ok");
662  // Rename docs starting with $oldref with $newref
663  $listoffiles = dol_dir_list($conf->bom->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
664  foreach ($listoffiles as $fileentry) {
665  $dirsource = $fileentry['name'];
666  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
667  $dirsource = $fileentry['path'].'/'.$dirsource;
668  $dirdest = $fileentry['path'].'/'.$dirdest;
669  @rename($dirsource, $dirdest);
670  }
671  }
672  }
673  }
674  }
675 
676  // Set new ref and current status
677  if (!$error) {
678  $this->ref = $num;
679  $this->status = self::STATUS_VALIDATED;
680  }
681 
682  if (!$error) {
683  $this->db->commit();
684  return 1;
685  } else {
686  $this->db->rollback();
687  return -1;
688  }
689  }
690 
698  public function setDraft($user, $notrigger = 0)
699  {
700  // Protection
701  if ($this->status <= self::STATUS_DRAFT) {
702  return 0;
703  }
704 
705  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->write))
706  || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->bom_advance->validate))))
707  {
708  $this->error='Permission denied';
709  return -1;
710  }*/
711 
712  return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'BOM_UNVALIDATE');
713  }
714 
722  public function cancel($user, $notrigger = 0)
723  {
724  // Protection
725  if ($this->status != self::STATUS_VALIDATED) {
726  return 0;
727  }
728 
729  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->write))
730  || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->bom_advance->validate))))
731  {
732  $this->error='Permission denied';
733  return -1;
734  }*/
735 
736  return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'BOM_CLOSE');
737  }
738 
746  public function reopen($user, $notrigger = 0)
747  {
748  // Protection
749  if ($this->status != self::STATUS_CANCELED) {
750  return 0;
751  }
752 
753  /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->write))
754  || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->bom_advance->validate))))
755  {
756  $this->error='Permission denied';
757  return -1;
758  }*/
759 
760  return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'BOM_REOPEN');
761  }
762 
763 
774  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
775  {
776  global $db, $conf, $langs, $hookmanager;
777 
778  if (!empty($conf->dol_no_mouse_hover)) {
779  $notooltip = 1; // Force disable tooltips
780  }
781 
782  $result = '';
783 
784  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("BillOfMaterials").'</u>';
785  if (isset($this->status)) {
786  $label .= ' '.$this->getLibStatut(5);
787  }
788  $label .= '<br>';
789  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
790  if (isset($this->label)) {
791  $label .= '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
792  }
793  if (!empty($this->fk_product) && $this->fk_product > 0) {
794  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
795  $product = new Product($db);
796  $resultFetch = $product->fetch($this->fk_product);
797  if ($resultFetch > 0) {
798  $label .= "<br><b>".$langs->trans("Product").'</b>: '.$product->ref.' - '.$product->label;
799  }
800  }
801 
802 
803  $url = DOL_URL_ROOT.'/bom/bom_card.php?id='.$this->id;
804 
805  if ($option != 'nolink') {
806  // Add param to save lastsearch_values or not
807  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
808  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
809  $add_save_lastsearch_values = 1;
810  }
811  if ($add_save_lastsearch_values) {
812  $url .= '&save_lastsearch_values=1';
813  }
814  }
815 
816  $linkclose = '';
817  if (empty($notooltip)) {
818  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
819  $label = $langs->trans("ShowBillOfMaterials");
820  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
821  }
822  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
823  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
824  } else {
825  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
826  }
827 
828  $linkstart = '<a href="'.$url.'"';
829  $linkstart .= $linkclose.'>';
830  $linkend = '</a>';
831 
832  $result .= $linkstart;
833  if ($withpicto) {
834  $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);
835  }
836  if ($withpicto != 2) {
837  $result .= $this->ref;
838  }
839  $result .= $linkend;
840  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
841 
842  global $action, $hookmanager;
843  $hookmanager->initHooks(array('bomdao'));
844  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
845  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
846  if ($reshook > 0) {
847  $result = $hookmanager->resPrint;
848  } else {
849  $result .= $hookmanager->resPrint;
850  }
851 
852  return $result;
853  }
854 
861  public function getLibStatut($mode = 0)
862  {
863  return $this->LibStatut($this->status, $mode);
864  }
865 
866  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
874  public function LibStatut($status, $mode = 0)
875  {
876  // phpcs:enable
877  if (empty($this->labelStatus)) {
878  global $langs;
879  //$langs->load("mrp");
880  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
881  $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
882  $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
883  }
884 
885  $statusType = 'status'.$status;
886  if ($status == self::STATUS_VALIDATED) {
887  $statusType = 'status4';
888  }
889  if ($status == self::STATUS_CANCELED) {
890  $statusType = 'status6';
891  }
892 
893  return dolGetStatus($this->labelStatus[$status], $this->labelStatus[$status], '', $statusType, $mode);
894  }
895 
902  public function info($id)
903  {
904  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
905  $sql .= ' fk_user_creat, fk_user_modif';
906  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
907  $sql .= ' WHERE t.rowid = '.((int) $id);
908  $result = $this->db->query($sql);
909  if ($result) {
910  if ($this->db->num_rows($result)) {
911  $obj = $this->db->fetch_object($result);
912  $this->id = $obj->rowid;
913 
914  $this->user_creation_id = $obj->fk_user_creat;
915  $this->user_modification_id = $obj->fk_user_modif;
916  $this->date_creation = $this->db->jdate($obj->datec);
917  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
918  }
919 
920  $this->db->free($result);
921  } else {
922  dol_print_error($this->db);
923  }
924  }
925 
931  public function getLinesArray()
932  {
933  $this->lines = array();
934 
935  $objectline = new BOMLine($this->db);
936  $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_bom = '.((int) $this->id)));
937 
938  if (is_numeric($result)) {
939  $this->error = $objectline->error;
940  $this->errors = $objectline->errors;
941  return $result;
942  } else {
943  $this->lines = $result;
944  return $this->lines;
945  }
946  }
947 
959  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
960  {
961  global $conf, $langs;
962 
963  $langs->load("mrp");
964  $outputlangs->load("products");
965 
966  if (!dol_strlen($modele)) {
967  $modele = 'standard';
968 
969  if ($this->model_pdf) {
970  $modele = $this->model_pdf;
971  } elseif (!empty($conf->global->BOM_ADDON_PDF)) {
972  $modele = $conf->global->BOM_ADDON_PDF;
973  }
974  }
975 
976  $modelpath = "core/modules/bom/doc/";
977 
978  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
979  }
980 
987  public function initAsSpecimen()
988  {
989  $this->initAsSpecimenCommon();
990  $this->ref = 'BOM-123';
991  $this->date = $this->date_creation;
992  }
993 
994 
1001  public function doScheduledJob()
1002  {
1003  global $conf, $langs;
1004 
1005  //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1006 
1007  $error = 0;
1008  $this->output = '';
1009  $this->error = '';
1010 
1011  dol_syslog(__METHOD__, LOG_DEBUG);
1012 
1013  $now = dol_now();
1014 
1015  $this->db->begin();
1016 
1017  // ...
1018 
1019  $this->db->commit();
1020 
1021  return $error;
1022  }
1023 
1030  public function calculateCosts()
1031  {
1032  global $hookmanager;
1033 
1034  include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1035  $this->unit_cost = 0;
1036  $this->total_cost = 0;
1037 
1038  $parameters=array();
1039  $reshook = $hookmanager->executeHooks('calculateCostsBom', $parameters, $this); // Note that $action and $object may have been modified by hook
1040 
1041 
1042  if ($reshook > 0) {
1043  return $hookmanager->resPrint;
1044  }
1045 
1046  if (is_array($this->lines) && count($this->lines)) {
1047  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1048  $productFournisseur = new ProductFournisseur($this->db);
1049  $tmpproduct = new Product($this->db);
1050 
1051  foreach ($this->lines as &$line) {
1052  $tmpproduct->cost_price = 0;
1053  $tmpproduct->pmp = 0;
1054 
1055  if (empty($line->fk_bom_child)) {
1056  $result = $tmpproduct->fetch($line->fk_product, '', '', '', 0, 1, 1); // We discard selling price and language loading
1057  if ($result < 0) {
1058  $this->error = $tmpproduct->error;
1059  return -1;
1060  }
1061  $line->unit_cost = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
1062  if ((empty($line->unit_cost)) && ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0)) {
1063  if ($productFournisseur->fourn_remise_percent != "0") {
1064  $line->unit_cost = $productFournisseur->fourn_unitprice_with_discount;
1065  } else {
1066  $line->unit_cost = $productFournisseur->fourn_unitprice;
1067  }
1068  }
1069 
1070  $line->total_cost = price2num($line->qty * $line->unit_cost, 'MT');
1071 
1072  $this->total_cost += $line->total_cost;
1073  } else {
1074  $bom_child= new BOM($this->db);
1075  $res = $bom_child->fetch($line->fk_bom_child);
1076  if ($res>0) {
1077  $bom_child->calculateCosts();
1078  $line->childBom[] = $bom_child;
1079  $line->total_cost = price2num($bom_child->total_cost * $line->qty, 'MT');
1080  $this->total_cost += $line->total_cost;
1081  } else {
1082  $this->error = $bom_child->error;
1083  return -2;
1084  }
1085  }
1086  }
1087 
1088  $this->total_cost = price2num($this->total_cost, 'MT');
1089  if ($this->qty > 0) {
1090  $this->unit_cost = price2num($this->total_cost / $this->qty, 'MU');
1091  } elseif ($this->qty < 0) {
1092  $this->unit_cost = price2num($this->total_cost * $this->qty, 'MU');
1093  }
1094  }
1095  }
1096 
1105  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1106  {
1107  $tables = array(
1108  'bom_bomline'
1109  );
1110 
1111  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1112  }
1113 
1121  public function getNetNeeds(&$TNetNeeds = array(), $qty = 0)
1122  {
1123  if (! empty($this->lines)) {
1124  foreach ($this->lines as $line) {
1125  if (! empty($line->childBom)) {
1126  foreach ($line->childBom as $childBom) $childBom->getNetNeeds($TNetNeeds, $line->qty*$qty);
1127  } else {
1128  if (empty($TNetNeeds[$line->fk_product])) {
1129  $TNetNeeds[$line->fk_product] = 0;
1130  }
1131  $TNetNeeds[$line->fk_product] += $line->qty*$qty;
1132  }
1133  }
1134  }
1135  }
1136 
1145  public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0)
1146  {
1147  if (! empty($this->lines)) {
1148  foreach ($this->lines as $line) {
1149  if (! empty($line->childBom)) {
1150  foreach ($line->childBom as $childBom) {
1151  $TNetNeeds[$childBom->id]['bom'] = $childBom;
1152  $TNetNeeds[$childBom->id]['parentid'] = $this->id;
1153  $TNetNeeds[$childBom->id]['qty'] = $line->qty*$qty;
1154  $TNetNeeds[$childBom->id]['level'] = $level;
1155  $childBom->getNetNeedsTree($TNetNeeds, $line->qty*$qty, $level+1);
1156  }
1157  } else {
1158  $TNetNeeds[$this->id]['product'][$line->fk_product]['qty'] += $line->qty * $qty;
1159  $TNetNeeds[$this->id]['product'][$line->fk_product]['level'] = $level;
1160  }
1161  }
1162  }
1163  }
1164 
1173  public function getParentBomTreeRecursive(&$TParentBom, $bom_id = '', $level = 1)
1174  {
1175 
1176  // Protection against infinite loop
1177  if ($level > 1000) {
1178  return;
1179  }
1180 
1181  if (empty($bom_id)) $bom_id=$this->id;
1182 
1183  $sql = 'SELECT l.fk_bom, b.label
1184  FROM '.MAIN_DB_PREFIX.'bom_bomline l
1185  INNER JOIN '.MAIN_DB_PREFIX.$this->table_element.' b ON b.rowid = l.fk_bom
1186  WHERE fk_bom_child = '.((int) $bom_id);
1187 
1188  $resql = $this->db->query($sql);
1189  if (!empty($resql)) {
1190  while ($res = $this->db->fetch_object($resql)) {
1191  $TParentBom[$res->fk_bom] = $res->fk_bom;
1192  $this->getParentBomTreeRecursive($TParentBom, $res->fk_bom, $level+1);
1193  }
1194  }
1195  }
1196 }
1197 
1198 
1203 {
1207  public $element = 'bomline';
1208 
1212  public $table_element = 'bom_bomline';
1213 
1217  public $ismultientitymanaged = 0;
1218 
1222  public $isextrafieldmanaged = 1;
1223 
1227  public $picto = 'bomline';
1228 
1229 
1249  // BEGIN MODULEBUILDER PROPERTIES
1253  public $fields = array(
1254  'rowid' => array('type'=>'integer', 'label'=>'LineID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
1255  'fk_bom' => array('type'=>'integer:BillOfMaterials:societe/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1,),
1256  'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
1257  'fk_bom_child' => array('type'=>'integer:BOM:bom/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>-1, 'position'=>40, 'notnull'=>-1,),
1258  'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
1259  'qty' => array('type'=>'double(24,8)', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'position'=>100, 'notnull'=>1, 'isameasure'=>'1',),
1260  'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
1261  'disable_stock_change' => array('type'=>'smallint', 'label'=>'DisableStockChange', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>108, 'css'=>'maxwidth50imp', 'help'=>'DisableStockChangeHelp'),
1262  'efficiency' => array('type'=>'double(24,8)', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'position'=>110, 'notnull'=>1, 'css'=>'maxwidth50imp', 'help'=>'ValueOfEfficiencyConsumedMeans'),
1263  'position' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>1, 'visible'=>0, 'default'=>0, 'position'=>200, 'notnull'=>1,),
1264  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
1265  );
1266 
1270  public $rowid;
1271 
1275  public $fk_bom;
1276 
1280  public $fk_product;
1281 
1285  public $fk_bom_child;
1286 
1290  public $description;
1291  public $qty;
1292 
1296  public $qty_frozen;
1297  public $disable_stock_change;
1298  public $efficiency;
1299 
1303  public $position;
1304 
1308  public $import_key;
1309  // END MODULEBUILDER PROPERTIES
1310 
1314  public $total_cost = 0;
1315 
1319  public $unit_cost = 0;
1320 
1321 
1325  public $childBom = array();
1326 
1327 
1333  public function __construct(DoliDB $db)
1334  {
1335  global $conf, $langs;
1336 
1337  $this->db = $db;
1338 
1339  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
1340  $this->fields['rowid']['visible'] = 0;
1341  }
1342  if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) {
1343  $this->fields['entity']['enabled'] = 0;
1344  }
1345 
1346  // Unset fields that are disabled
1347  foreach ($this->fields as $key => $val) {
1348  if (isset($val['enabled']) && empty($val['enabled'])) {
1349  unset($this->fields[$key]);
1350  }
1351  }
1352 
1353  // Translate some data of arrayofkeyval
1354  foreach ($this->fields as $key => $val) {
1355  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
1356  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
1357  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
1358  }
1359  }
1360  }
1361  }
1362 
1370  public function create(User $user, $notrigger = false)
1371  {
1372  if ($this->efficiency < 0 || $this->efficiency > 1) {
1373  $this->efficiency = 1;
1374  }
1375 
1376  return $this->createCommon($user, $notrigger);
1377  }
1378 
1386  public function fetch($id, $ref = null)
1387  {
1388  $result = $this->fetchCommon($id, $ref);
1389  //if ($result > 0 && ! empty($this->table_element_line)) $this->fetchLines();
1390  return $result;
1391  }
1392 
1404  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
1405  {
1406  global $conf;
1407 
1408  dol_syslog(__METHOD__, LOG_DEBUG);
1409 
1410  $records = array();
1411 
1412  $sql = 'SELECT ';
1413  $sql .= $this->getFieldList();
1414  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1415  if ($this->ismultientitymanaged) {
1416  $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')';
1417  } else {
1418  $sql .= ' WHERE 1 = 1';
1419  }
1420  // Manage filter
1421  $sqlwhere = array();
1422  if (count($filter) > 0) {
1423  foreach ($filter as $key => $value) {
1424  if ($key == 't.rowid') {
1425  $sqlwhere[] = $key." = ".((int) $value);
1426  } elseif (strpos($key, 'date') !== false) {
1427  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
1428  } elseif ($key == 'customsql') {
1429  $sqlwhere[] = $value;
1430  } else {
1431  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
1432  }
1433  }
1434  }
1435  if (count($sqlwhere) > 0) {
1436  $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
1437  }
1438 
1439  if (!empty($sortfield)) {
1440  $sql .= $this->db->order($sortfield, $sortorder);
1441  }
1442  if (!empty($limit)) {
1443  $sql .= $this->db->plimit($limit, $offset);
1444  }
1445 
1446  $resql = $this->db->query($sql);
1447  if ($resql) {
1448  $num = $this->db->num_rows($resql);
1449 
1450  while ($obj = $this->db->fetch_object($resql)) {
1451  $record = new self($this->db);
1452  $record->setVarsFromFetchObj($obj);
1453 
1454  $records[$record->id] = $record;
1455  }
1456  $this->db->free($resql);
1457 
1458  return $records;
1459  } else {
1460  $this->errors[] = 'Error '.$this->db->lasterror();
1461  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1462 
1463  return -1;
1464  }
1465  }
1466 
1474  public function update(User $user, $notrigger = false)
1475  {
1476  if ($this->efficiency < 0 || $this->efficiency > 1) {
1477  $this->efficiency = 1;
1478  }
1479 
1480  return $this->updateCommon($user, $notrigger);
1481  }
1482 
1490  public function delete(User $user, $notrigger = false)
1491  {
1492  return $this->deleteCommon($user, $notrigger);
1493  //return $this->deleteCommon($user, $notrigger, 1);
1494  }
1495 
1506  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1507  {
1508  global $db, $conf, $langs, $hookmanager;
1509 
1510  if (!empty($conf->dol_no_mouse_hover)) {
1511  $notooltip = 1; // Force disable tooltips
1512  }
1513 
1514  $result = '';
1515 
1516  $label = '<u>'.$langs->trans("BillOfMaterialsLine").'</u>';
1517  $label .= '<br>';
1518  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1519 
1520  $url = DOL_URL_ROOT.'/bom/bomline_card.php?id='.$this->id;
1521 
1522  if ($option != 'nolink') {
1523  // Add param to save lastsearch_values or not
1524  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1525  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1526  $add_save_lastsearch_values = 1;
1527  }
1528  if ($add_save_lastsearch_values) {
1529  $url .= '&save_lastsearch_values=1';
1530  }
1531  }
1532 
1533  $linkclose = '';
1534  if (empty($notooltip)) {
1535  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1536  $label = $langs->trans("ShowBillOfMaterialsLine");
1537  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1538  }
1539  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1540  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1541  } else {
1542  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1543  }
1544 
1545  $linkstart = '<a href="'.$url.'"';
1546  $linkstart .= $linkclose.'>';
1547  $linkend = '</a>';
1548 
1549  $result .= $linkstart;
1550  if ($withpicto) {
1551  $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);
1552  }
1553  if ($withpicto != 2) {
1554  $result .= $this->ref;
1555  }
1556  $result .= $linkend;
1557  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1558 
1559  global $action, $hookmanager;
1560  $hookmanager->initHooks(array('bomlinedao'));
1561  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1562  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1563  if ($reshook > 0) {
1564  $result = $hookmanager->resPrint;
1565  } else {
1566  $result .= $hookmanager->resPrint;
1567  }
1568 
1569  return $result;
1570  }
1571 
1578  public function getLibStatut($mode = 0)
1579  {
1580  return $this->LibStatut($this->status, $mode);
1581  }
1582 
1583  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1591  public function LibStatut($status, $mode = 0)
1592  {
1593  // phpcs:enable
1594  return '';
1595  }
1596 
1603  public function info($id)
1604  {
1605  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1606  $sql .= ' fk_user_creat, fk_user_modif';
1607  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1608  $sql .= ' WHERE t.rowid = '.((int) $id);
1609  $result = $this->db->query($sql);
1610  if ($result) {
1611  if ($this->db->num_rows($result)) {
1612  $obj = $this->db->fetch_object($result);
1613  $this->id = $obj->rowid;
1614  $this->user_creation_id = $obj->fk_user_creat;
1615  $this->user_modification_id = $obj->fk_user_modif;
1616  $this->date_creation = $this->db->jdate($obj->datec);
1617  $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1618  }
1619  $this->db->free($result);
1620  } else {
1621  dol_print_error($this->db);
1622  }
1623  }
1624 
1631  public function initAsSpecimen()
1632  {
1633  $this->initAsSpecimenCommon();
1634  }
1635 }
CommonObject\deleteCommon
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
Definition: commonobject.class.php:9406
CommonObject\setStatusCommon
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
Definition: commonobject.class.php:9683
db
$conf db
API class for accounts.
Definition: inc.php:41
CommonObject\fetchCommon
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9202
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1226
CommonObject\copy_linked_contact
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
Definition: commonobject.class.php:1217
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:1404
ProductFournisseur
Class to manage predefined suppliers products.
Definition: fournisseur.product.class.php:41
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:4844
BOMLine\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:1578
BOMLine
Class for BOMLine.
Definition: bom.class.php:1202
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1062
BOM\create
create(User $user, $notrigger=false)
Create object into database.
Definition: bom.class.php:271
CommonObject\fetchLinesCommon
fetchLinesCommon($morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9258
BOM\calculateCosts
calculateCosts()
BOM costs calculation based on cost_price or pmp of each BOM line.
Definition: bom.class.php:1030
BOM\getLibStatut
getLibStatut($mode=0)
Return label of the status.
Definition: bom.class.php:861
BOM\getNetNeedsTree
getNetNeedsTree(&$TNetNeeds=array(), $qty=0, $level=0)
Get Net needs Tree by product or bom.
Definition: bom.class.php:1145
ref
$object ref
Definition: info.php:77
CommonObject\commonReplaceProduct
static commonReplaceProduct(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
Definition: commonobject.class.php:8376
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)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
CommonObject\initAsSpecimenCommon
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: commonobject.class.php:9733
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:44
BOMLine\__construct
__construct(DoliDB $db)
Constructor.
Definition: bom.class.php:1333
BOM
Class for BOM.
Definition: bom.class.php:34
BOM\getNextNumRef
getNextNumRef($prod)
Returns the reference to the following non used BOM depending on the active numbering module defined ...
Definition: bom.class.php:531
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
BOMLine\LibStatut
LibStatut($status, $mode=0)
Return the status.
Definition: bom.class.php:1591
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:3880
BOM\replaceProduct
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
Definition: bom.class.php:1105
BOMLine\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:1631
BOM\cancel
cancel($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:722
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:5406
CommonObject\createCommon
createCommon(User $user, $notrigger=false)
Create object into database.
Definition: commonobject.class.php:9035
BOM\createFromClone
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition: bom.class.php:287
BOM\reopen
reopen($user, $notrigger=0)
Set cancel status.
Definition: bom.class.php:746
BOMLine\create
create(User $user, $notrigger=false)
Create object into database.
Definition: bom.class.php:1370
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:1506
BOMLine\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bom.class.php:1474
BOMLine\info
info($id)
Load the info information in the object.
Definition: bom.class.php:1603
BOM\deleteLine
deleteLine(User $user, $idline, $notrigger=false)
Delete a line of object in database.
Definition: bom.class.php:514
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:1173
BOM\getLinesArray
getLinesArray()
Create an array of lines.
Definition: bom.class.php:931
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
BOM\getNetNeeds
getNetNeeds(&$TNetNeeds=array(), $qty=0)
Get Net needs by product.
Definition: bom.class.php:1121
BOM\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:378
BOM\__construct
__construct(DoliDB $db)
Constructor.
Definition: bom.class.php:234
BOM\validate
validate($user, $notrigger=0)
Validate bom.
Definition: bom.class.php:579
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:414
CommonObject\updateCommon
updateCommon(User $user, $notrigger=false)
Update object into database.
Definition: commonobject.class.php:9308
BOM\doScheduledJob
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
Definition: bom.class.php:1001
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3747
CommonObject\fetch_product
fetch_product()
Load the product with id $this->fk_product into this->product.
Definition: commonobject.class.php:1891
User
Class to manage Dolibarr users.
Definition: user.class.php:44
BOM\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bom.class.php:484
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:874
BOM\setDraft
setDraft($user, $notrigger=0)
Set draft status.
Definition: bom.class.php:698
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10338
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:4211
BOM\fetchLines
fetchLines()
Load object lines in memory from the database.
Definition: bom.class.php:395
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:774
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->supplier_invoice->lire)) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
BOM\info
info($id)
Load the info information in the object.
Definition: bom.class.php:902
CommonObject\deleteLineCommon
deleteLineCommon(User $user, $idline, $notrigger=false)
Delete a line of object in database.
Definition: commonobject.class.php:9622
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5791
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:959
CommonObject\getFieldList
getFieldList($alias='')
Function to concat keys of fields.
Definition: commonobject.class.php:8987
BOM\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: bom.class.php:987
BOMLine\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: bom.class.php:1386