dolibarr  19.0.0-dev
bom_card.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2017-2023 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.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 // Load Dolibarr environment
26 require '../main.inc.php';
27 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
28 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
29 require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/bom/lib/bom.lib.php';
31 require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp.lib.php';
32 
33 
34 // Load translation files required by the page
35 $langs->loadLangs(array('mrp', 'other'));
36 
37 // Get parameters
38 $id = GETPOST('id', 'int');
39 $lineid = GETPOST('lineid', 'int');
40 $ref = GETPOST('ref', 'alpha');
41 $action = GETPOST('action', 'aZ09');
42 $confirm = GETPOST('confirm', 'alpha');
43 $cancel = GETPOST('cancel', 'aZ09');
44 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'bomcard'; // To manage different context of search
45 $backtopage = GETPOST('backtopage', 'alpha');
46 
47 
48 // PDF
49 $hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0));
50 $hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0));
51 $hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
52 
53 // Initialize technical objects
54 $object = new BOM($db);
55 $extrafields = new ExtraFields($db);
56 $diroutputmassaction = $conf->bom->dir_output.'/temp/massgeneration/'.$user->id;
57 $hookmanager->initHooks(array('bomcard', 'globalcard')); // Note that conf->hooks_modules contains array
58 
59 // Fetch optionals attributes and labels
60 $extrafields->fetch_name_optionals_label($object->table_element);
61 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
62 
63 // Initialize array of search criterias
64 $search_all = GETPOST("search_all", 'alpha');
65 $search = array();
66 foreach ($object->fields as $key => $val) {
67  if (GETPOST('search_'.$key, 'alpha')) {
68  $search[$key] = GETPOST('search_'.$key, 'alpha');
69  }
70 }
71 
72 if (empty($action) && empty($id) && empty($ref)) {
73  $action = 'view';
74 }
75 
76 // Load object
77 include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once.
78 if ($object->id > 0) {
79  $object->calculateCosts();
80 }
81 
82 
83 // Security check - Protection if external user
84 //if ($user->socid > 0) accessforbidden();
85 //if ($user->socid > 0) $socid = $user->socid;
86 $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
87 $result = restrictedArea($user, 'bom', $object->id, $object->table_element, '', '', 'rowid', $isdraft);
88 
89 // Permissions
90 $permissionnote = $user->hasRight('bom', 'write'); // Used by the include of actions_setnotes.inc.php
91 $permissiondellink = $user->hasRight('bom', 'write'); // Used by the include of actions_dellink.inc.php
92 $permissiontoadd = $user->hasRight('bom', 'write'); // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
93 $permissiontodelete = $user->hasRight('bom', 'delete') || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT);
94 $upload_dir = $conf->bom->multidir_output[isset($object->entity) ? $object->entity : 1];
95 
96 
97 /*
98  * Actions
99  */
100 
101 $parameters = array();
102 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
103 if ($reshook < 0) {
104  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
105 }
106 
107 if (empty($reshook)) {
108  $error = 0;
109 
110  $backurlforlist = DOL_URL_ROOT.'/bom/bom_list.php';
111 
112  if (empty($backtopage) || ($cancel && empty($id))) {
113  if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
114  if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
115  $backtopage = $backurlforlist;
116  } else {
117  $backtopage = DOL_URL_ROOT.'/bom/bom_card.php?id='.($id > 0 ? $id : '__ID__');
118  }
119  }
120  }
121 
122  $triggermodname = 'BOM_MODIFY'; // Name of trigger action code to execute when we modify record
123 
124 
125  // Actions cancel, add, update, delete or clone
126  include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
127  // The fetch/fetch_lines was redone into the inc.php so we must recall the calculateCosts()
128  if ($action == 'confirm_validate' && $object->id > 0) {
129  $object->calculateCosts();
130  }
131 
132  // Actions when linking object each other
133  include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php';
134 
135  // Actions when printing a doc from card
136  include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
137 
138  // Action to move up and down lines of object
139  //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php';
140 
141  // Action to build doc
142  include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
143 
144  // Actions to send emails
145  $triggersendname = 'BOM_SENTBYMAIL';
146  $autocopy = 'MAIN_MAIL_AUTOCOPY_BOM_TO';
147  $trackid = 'bom'.$object->id;
148  include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
149 
150  // Add line
151  if ($action == 'addline' && $user->rights->bom->write) {
152  $langs->load('errors');
153  $error = 0;
154  $predef = '';
155 
156  // Set if we used free entry or predefined product
157  $bom_child_id = (int) GETPOST('bom_id', 'int');
158  if ($bom_child_id > 0) {
159  $bom_child = new BOM($db);
160  $res = $bom_child->fetch($bom_child_id);
161  if ($res) {
162  $idprod = $bom_child->fk_product;
163  }
164  } else {
165  $idprod = (!empty(GETPOST('idprodservice', 'int')) ? GETPOST('idprodservice', 'int') : (int) GETPOST('idprod', 'int'));
166  }
167 
168  $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
169  $qty_frozen = price2num(GETPOST('qty_frozen', 'alpha'), 'MS');
170  $disable_stock_change = GETPOST('disable_stock_change', 'int');
171  $efficiency = price2num(GETPOST('efficiency', 'alpha'));
172  $fk_unit = GETPOST('fk_unit', 'alphanohtml');
173 
174  if (!empty($idprod) && $conf->workstation->enabled) {
175  $product = new Product($db);
176  $res = $product->fetch($idprod);
177  if ($res > 0 && $product->type == Product::TYPE_SERVICE) $fk_default_workstation = $product->fk_default_workstation;
178  }
179 
180  if ($qty == '') {
181  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
182  $error++;
183  }
184  if (!($idprod > 0)) {
185  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Product')), null, 'errors');
186  $error++;
187  }
188 
189  if ($object->fk_product == $idprod) {
190  setEventMessages($langs->trans('TheProductXIsAlreadyTheProductToProduce'), null, 'errors');
191  $error++;
192  }
193 
194  // We check if we're allowed to add this bom
195  $TParentBom=array();
196  $object->getParentBomTreeRecursive($TParentBom);
197  if ($bom_child_id > 0 && !empty($TParentBom) && in_array($bom_child_id, $TParentBom)) {
198  $n_child = new BOM($db);
199  $n_child->fetch($bom_child_id);
200  setEventMessages($langs->transnoentities('BomCantAddChildBom', $n_child->getNomUrl(1), $object->getNomUrl(1)), null, 'errors');
201  $error++;
202  }
203 
204  if (!$error) {
205  // Extrafields
206  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
207  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
208  // Unset extrafield
209  if (is_array($extralabelsline)) {
210  // Get extra fields
211  foreach ($extralabelsline as $key => $value) {
212  unset($_POST["options_".$key]);
213  }
214  }
215 
216  $result = $object->addLine($idprod, $qty, $qty_frozen, $disable_stock_change, $efficiency, -1, $bom_child_id, null, $fk_unit, $array_options, $fk_default_workstation);
217 
218  if ($result <= 0) {
219  setEventMessages($object->error, $object->errors, 'errors');
220  $action = '';
221  } else {
222  unset($_POST['idprod']);
223  unset($_POST['idprodservice']);
224  unset($_POST['qty']);
225  unset($_POST['qty_frozen']);
226  unset($_POST['disable_stock_change']);
227  }
228 
229  $object->fetchLines();
230 
231  $object->calculateCosts();
232  }
233  }
234 
235  // Update line
236  if ($action == 'updateline' && $user->rights->bom->write) {
237  $langs->load('errors');
238  $error = 0;
239 
240  // Set if we used free entry or predefined product
241  $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
242  $qty_frozen = price2num(GETPOST('qty_frozen', 'alpha'), 'MS');
243  $disable_stock_change = GETPOST('disable_stock_change', 'int');
244  $efficiency = price2num(GETPOST('efficiency', 'alpha'));
245  $fk_unit = GETPOST('fk_unit', 'alphanohtml');
246 
247  if ($qty == '') {
248  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
249  $error++;
250  }
251 
252  if (!$error) {
253  // Extrafields
254  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
255  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
256  // Unset extrafield
257  if (is_array($extralabelsline)) {
258  // Get extra fields
259  foreach ($extralabelsline as $key => $value) {
260  unset($_POST["options_".$key]);
261  }
262  }
263 
264  $bomline = new BOMLine($db);
265  $bomline->fetch($lineid);
266 
267  $result = $object->updateLine($lineid, $qty, (int) $qty_frozen, (int) $disable_stock_change, $efficiency, $bomline->position, $bomline->import_key, $fk_unit, $array_options);
268 
269  if ($result <= 0) {
270  setEventMessages($object->error, $object->errors, 'errors');
271  $action = '';
272  } else {
273  unset($_POST['idprod']);
274  unset($_POST['idprodservice']);
275  unset($_POST['qty']);
276  unset($_POST['qty_frozen']);
277  unset($_POST['disable_stock_change']);
278  }
279 
280  $object->fetchLines();
281 
282  $object->calculateCosts();
283  }
284  }
285 }
286 
287 
288 /*
289  * View
290  */
291 
292 $form = new Form($db);
293 $formfile = new FormFile($db);
294 
295 
296 $title = $langs->trans('BOM');
297 $help_url ='EN:Module_BOM';
298 llxHeader('', $title, $help_url);
299 
300 // Part to create
301 if ($action == 'create') {
302  print load_fiche_titre($langs->trans("NewBOM"), '', 'bom');
303 
304  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
305  print '<input type="hidden" name="token" value="'.newToken().'">';
306  print '<input type="hidden" name="action" value="add">';
307  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
308 
309  print dol_get_fiche_head(array(), '');
310 
311  print '<table class="border centpercent tableforfieldcreate">'."\n";
312 
313  // Common attributes
314  include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_add.tpl.php';
315 
316  // Other attributes
317  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
318 
319  print '</table>'."\n";
320 
321  print dol_get_fiche_end();
322 
323  print $form->buttonsSaveCancel("Create");
324 
325  print '</form>';
326 }
327 
328 // Part to edit record
329 if (($id || $ref) && $action == 'edit') {
330  print load_fiche_titre($langs->trans("BillOfMaterials"), '', 'cubes');
331 
332  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
333  print '<input type="hidden" name="token" value="'.newToken().'">';
334  print '<input type="hidden" name="action" value="update">';
335  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
336  print '<input type="hidden" name="id" value="'.$object->id.'">';
337 
338  print dol_get_fiche_head();
339 
340  //$object->fields['keyfield']['disabled'] = 1;
341 
342  print '<table class="border centpercent tableforfieldedit">'."\n";
343 
344  // Common attributes
345  include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_edit.tpl.php';
346 
347  // Other attributes
348  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_edit.tpl.php';
349 
350  print '</table>';
351 
352  print dol_get_fiche_end();
353 
354  print $form->buttonsSaveCancel("Create");
355 
356  print '</form>';
357 }
358 
359 // Part to show record
360 if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
361  $head = bomPrepareHead($object);
362  print dol_get_fiche_head($head, 'card', $langs->trans("BillOfMaterials"), -1, 'bom');
363 
364  $formconfirm = '';
365 
366  // Confirmation to delete
367  if ($action == 'delete') {
368  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteBillOfMaterials'), $langs->trans('ConfirmDeleteBillOfMaterials'), 'confirm_delete', '', 0, 1);
369  }
370  // Confirmation to delete line
371  if ($action == 'deleteline') {
372  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
373  }
374 
375  // Confirmation of validation
376  if ($action == 'validate') {
377  // We check that object has a temporary ref
378  $ref = substr($object->ref, 1, 4);
379  if ($ref == 'PROV') {
380  $object->fetch_product();
381  $numref = $object->getNextNumRef($object->product);
382  } else {
383  $numref = $object->ref;
384  }
385 
386  $text = $langs->trans('ConfirmValidateBom', $numref);
387  /*if (isModEnabled('notification'))
388  {
389  require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
390  $notify = new Notify($db);
391  $text .= '<br>';
392  $text .= $notify->confirmMessage('BOM_VALIDATE', $object->socid, $object);
393  }*/
394 
395  $formquestion = array();
396  if (isModEnabled('bom')) {
397  $langs->load("mrp");
398  $forcecombo = 0;
399  if ($conf->browser->name == 'ie') {
400  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
401  }
402  $formquestion = array(
403  // 'text' => $langs->trans("ConfirmClone"),
404  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
405  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
406  );
407  }
408 
409  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
410  }
411 
412  // Confirmation of closing
413  if ($action == 'close') {
414  $text = $langs->trans('ConfirmCloseBom', $object->ref);
415  /*if (isModEnabled('notification'))
416  {
417  require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
418  $notify = new Notify($db);
419  $text .= '<br>';
420  $text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
421  }*/
422 
423  $formquestion = array();
424  if (isModEnabled('bom')) {
425  $langs->load("mrp");
426  $forcecombo = 0;
427  if ($conf->browser->name == 'ie') {
428  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
429  }
430  $formquestion = array(
431  // 'text' => $langs->trans("ConfirmClone"),
432  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
433  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
434  );
435  }
436 
437  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
438  }
439 
440  // Confirmation of reopen
441  if ($action == 'reopen') {
442  $text = $langs->trans('ConfirmReopenBom', $object->ref);
443  /*if (isModEnabled('notification'))
444  {
445  require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
446  $notify = new Notify($db);
447  $text .= '<br>';
448  $text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
449  }*/
450 
451  $formquestion = array();
452  if (isModEnabled('bom')) {
453  $langs->load("mrp");
454  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
455  $forcecombo = 0;
456  if ($conf->browser->name == 'ie') {
457  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
458  }
459  $formquestion = array(
460  // 'text' => $langs->trans("ConfirmClone"),
461  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
462  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
463  );
464  }
465 
466  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $text, 'confirm_reopen', $formquestion, 0, 1, 220);
467  }
468 
469  // Clone confirmation
470  if ($action == 'clone') {
471  // Create an array for form
472  $formquestion = array();
473  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneBillOfMaterials', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
474  }
475 
476  // Confirmation of action xxxx
477  if ($action == 'setdraft') {
478  $text = $langs->trans('ConfirmSetToDraft', $object->ref);
479 
480  $formquestion = array();
481  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220);
482  }
483 
484  // Call Hook formConfirm
485  $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
486  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
487  if (empty($reshook)) {
488  $formconfirm .= $hookmanager->resPrint;
489  } elseif ($reshook > 0) {
490  $formconfirm = $hookmanager->resPrint;
491  }
492 
493  // Print form confirm
494  print $formconfirm;
495 
496 
497  // Object card
498  // ------------------------------------------------------------
499  $linkback = '<a href="'.DOL_URL_ROOT.'/bom/bom_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
500 
501  $morehtmlref = '<div class="refidno">';
502  /*
503  // Ref bis
504  $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', 0, 1);
505  $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', null, null, '', 1);
506  // Thirdparty
507  $morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1);
508  // Project
509  if (isModEnabled('project'))
510  {
511  $langs->load("projects");
512  $morehtmlref.='<br>'.$langs->trans('Project') . ' ';
513  if ($permissiontoadd)
514  {
515  if ($action != 'classify')
516  $morehtmlref.='<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token='.newToken().'&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> : ';
517  if ($action == 'classify') {
518  //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
519  $morehtmlref.='<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
520  $morehtmlref.='<input type="hidden" name="action" value="classin">';
521  $morehtmlref.='<input type="hidden" name="token" value="'.newToken().'">';
522  $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1);
523  $morehtmlref.='<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
524  $morehtmlref.='</form>';
525  } else {
526  $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
527  }
528  } else {
529  if (! empty($object->fk_project)) {
530  $proj = new Project($db);
531  $proj->fetch($object->fk_project);
532  $morehtmlref.=$proj->getNomUrl();
533  } else {
534  $morehtmlref.='';
535  }
536  }
537  }
538  */
539  $morehtmlref .= '</div>';
540 
541 
542  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
543 
544 
545  print '<div class="fichecenter">';
546  print '<div class="fichehalfleft">';
547  print '<div class="underbanner clearboth"></div>';
548  print '<table class="border centpercent tableforfield">'."\n";
549 
550  // Common attributes
551  $keyforbreak = 'duration';
552  include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
553  $object->calculateCosts();
554  print '<tr><td>'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).'</td><td><span class="amount">'.price($object->total_cost).'</span></td></tr>';
555  print '<tr><td>'.$langs->trans("UnitCost").'</td><td>'.price($object->unit_cost).'</td></tr>';
556 
557  // Other attributes
558  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
559 
560  print '</table>';
561  print '</div>';
562  print '</div>';
563 
564  print '<div class="clearboth"></div>';
565 
566  print dol_get_fiche_end();
567 
568 
569 
570  /*
571  * Lines
572  */
573 
574  if (!empty($object->table_element_line)) {
575  // Products
576  $res = $object->fetchLinesbytypeproduct(0); // Load all lines products into ->lines
577  $object->calculateCosts();
578 
579  print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product');
580 
581  print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '' : '') . '" method="POST">
582  <input type="hidden" name="token" value="' . newToken() . '">
583  <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
584  <input type="hidden" name="mode" value="">
585  <input type="hidden" name="page_y" value="">
586  <input type="hidden" name="id" value="' . $object->id . '">
587  ';
588 
589  if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
590  include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
591  }
592 
593  print '<div class="div-table-responsive-no-min">';
594  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
595  print '<table id="tablelines" class="noborder noshadow centpercent">';
596  }
597 
598  if (!empty($object->lines)) {
599  $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/bom/tpl');
600  }
601 
602  // Form to add new line
603  if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
604  if ($action != 'editline') {
605  // Add products/services form
606 
607 
608  $parameters = array();
609  $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
610  if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
611  if (empty($reshook))
612  $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
613  }
614  }
615 
616  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
617  print '</table>';
618  }
619  print '</div>';
620 
621  print "</form>\n";
622 
623  // Services
624  $filtertype = 1;
625  $res = $object->fetchLinesbytypeproduct(1); // Load all lines services into ->lines
626  $object->calculateCosts();
627 
628  print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service');
629 
630  print ' <form name="addservice" id="addservice" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '' : '') . '" method="POST">
631  <input type="hidden" name="token" value="' . newToken() . '">
632  <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
633  <input type="hidden" name="mode" value="">
634  <input type="hidden" name="page_y" value=""> <input type="hidden" name="id" value="' . $object->id . '">
635  ';
636 
637  if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
638  $tagidfortablednd = 'tablelinesservice';
639  include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
640  }
641 
642  print '<div class="div-table-responsive-no-min">';
643  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
644  print '<table id="tablelinesservice" class="noborder noshadow centpercent">';
645  }
646 
647  if (!empty($object->lines)) {
648  $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/bom/tpl');
649  }
650 
651  // Form to add new line
652  if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
653  if ($action != 'editline') {
654  // Add services form
655  $parameters = array();
656  $reshook = $hookmanager->executeHooks('formAddObjectServiceLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
657  if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
658  if (empty($reshook))
659  $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
660  }
661  }
662  }
663 
664  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
665  print '</table>';
666  }
667  print '</div>';
668 
669  print "</form>\n";
670 
671 
673 
674 
675  $res = $object->fetchLines();
676 
677  // Buttons for actions
678 
679  if ($action != 'presend' && $action != 'editline') {
680  print '<div class="tabsAction">'."\n";
681  $parameters = array();
682  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
683  if ($reshook < 0) {
684  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
685  }
686 
687  if (empty($reshook)) {
688  // Send
689  //if (empty($user->socid)) {
690  // print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendMail') . '</a>'."\n";
691  //}
692 
693  // Back to draft
694  if ($object->status == $object::STATUS_VALIDATED) {
695  if ($permissiontoadd) {
696  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=setdraft&token='.newToken().'">'.$langs->trans("SetToDraft").'</a>'."\n";
697  }
698  }
699 
700  // Modify
701  if ($object->status == $object::STATUS_DRAFT) {
702  if ($permissiontoadd) {
703  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>'."\n";
704  } else {
705  print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\n";
706  }
707  }
708 
709  // Validate
710  if ($object->status == $object::STATUS_DRAFT) {
711  if ($permissiontoadd) {
712  if (is_array($object->lines) && count($object->lines) > 0) {
713  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&amp;action=validate&amp;token='.newToken().'">'.$langs->trans("Validate").'</a>'."\n";
714  } else {
715  $langs->load("errors");
716  print '<a class="butActionRefused" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>'."\n";
717  }
718  }
719  }
720 
721  // Re-open
722  if ($permissiontoadd && $object->status == $object::STATUS_CANCELED) {
723  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reopen&token='.newToken().'">'.$langs->trans("ReOpen").'</a>'."\n";
724  }
725 
726  // Create MO
727  if (isModEnabled('mrp')) {
728  if ($object->status == $object::STATUS_VALIDATED && !empty($user->rights->mrp->write)) {
729  print '<a class="butAction" href="'.DOL_URL_ROOT.'/mrp/mo_card.php?action=create&fk_bom='.$object->id.'&token='.newToken().'&backtopageforcancel='.urlencode($_SERVER["PHP_SELF"].'?id='.$object->id).'">'.$langs->trans("CreateMO").'</a>'."\n";
730  }
731  }
732 
733  // Clone
734  if ($permissiontoadd) {
735  print dolGetButtonAction($langs->trans("ToClone"), '', 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.(!empty($object->socid) ? '&socid='.$object->socid : "").'&action=clone&object=bom', 'clone', $permissiontoadd);
736  }
737 
738  // Close / Cancel
739  if ($permissiontoadd && $object->status == $object::STATUS_VALIDATED) {
740  print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
741  }
742 
743  /*
744  if ($user->rights->bom->write)
745  {
746  if ($object->status == 1)
747  {
748  print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=disable&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
749  }
750  else
751  {
752  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=enable&token='.newToken().'">'.$langs->trans("Enable").'</a>'."\n";
753  }
754  }
755  */
756 
757  // Delete
758  print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete);
759  }
760  print '</div>'."\n";
761  }
762 
763 
764  // Select mail models is same action as presend
765  if (GETPOST('modelselected')) {
766  $action = 'presend';
767  }
768 
769  if ($action != 'presend') {
770  print '<div class="fichecenter"><div class="fichehalfleft">';
771  print '<a name="builddoc"></a>'; // ancre
772 
773  // Documents
774  $objref = dol_sanitizeFileName($object->ref);
775  $relativepath = $objref.'/'.$objref.'.pdf';
776  $filedir = $conf->bom->dir_output.'/'.$objref;
777  $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
778  $genallowed = $user->hasRight('bom', 'read'); // If you can read, you can build the PDF to read content
779  $delallowed = $user->hasRight('bom', 'write'); // If you can create/edit, you can remove a file on card
780  print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang);
781 
782  // Show links to link elements
783  $linktoelem = $form->showLinkToObjectBlock($object, null, array('bom'));
784  $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
785 
786 
787  print '</div><div class="fichehalfright">';
788 
789  $MAXEVENT = 10;
790 
791  $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/bom/bom_agenda.php?id='.$object->id);
792 
793  // List of actions on element
794  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
795  $formactions = new FormActions($db);
796  $somethingshown = $formactions->showactions($object, $object->element, 0, 1, '', $MAXEVENT, '', $morehtmlcenter);
797 
798  print '</div></div>';
799  }
800 
801  //Select mail models is same action as presend
802  if (GETPOST('modelselected')) {
803  $action = 'presend';
804  }
805 
806  // Presend form
807  $modelmail = 'bom';
808  $defaulttopic = 'InformationMessage';
809  $diroutput = $conf->bom->dir_output;
810  $trackid = 'bom'.$object->id;
811 
812  include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
813 }
814 
815 
816 // End of page
817 llxFooter();
818 $db->close();
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif($action=='specimen') elseif($action=='setmodel') elseif($action=='del') elseif($action=='setdoc') $formactions
View.
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
mrpCollapseBomManagement()
Manage collapse bom display.
Definition: bom.lib.php:152
bomPrepareHead($object)
Prepare array of tabs for BillOfMaterials.
Definition: bom.lib.php:78
Class for BOM.
Definition: bom.class.php:43
Class for BOMLine.
Definition: bom.class.php:1650
Class to manage standard extra fields.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class to manage products or services.
const TYPE_SERVICE
Service.
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
isModEnabled($module)
Is Dolibarr module enabled.
$formconfirm
if ($action == 'delbookkeepingyear') {
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.