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