dolibarr  18.0.0
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();
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1323
llxFooter
llxFooter()
Empty footer.
Definition: wrapper.php:70
load_fiche_titre
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
Definition: functions.lib.php:5477
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:609
FormActions
Class to manage building of HTML components.
Definition: html.formactions.class.php:30
BOMLine
Class for BOMLine.
Definition: bom.class.php:1645
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
BOM
Class for BOM.
Definition: bom.class.php:38
dol_banner_tab
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.
Definition: functions.lib.php:2205
$help_url
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
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5955
mrpCollapseBomManagement
mrpCollapseBomManagement()
Manage collapse bom display.
Definition: bom.lib.php:152
llxHeader
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
$formactions
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.
Definition: agenda_other.php:182
$formconfirm
$formconfirm
if ($action == 'delbookkeepingyear') {
Definition: listbyaccount.php:634
FormFile
Class to offer components to list and upload files.
Definition: html.formfile.class.php:36
dolGetButtonTitle
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.
Definition: functions.lib.php:11263
bomPrepareHead
bomPrepareHead($object)
Prepare array of tabs for BillOfMaterials.
Definition: bom.lib.php:78
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
Definition: functions.lib.php:8673
restrictedArea
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.
Definition: security.lib.php:353
newToken
newToken()
Return the value of token currently saved into session with name 'newtoken'.
Definition: functions.lib.php:11654
dol_get_fiche_end
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition: functions.lib.php:2177
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
dol_get_fiche_head
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.
Definition: functions.lib.php:1979
dolGetButtonAction
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
Definition: functions.lib.php:11080
ExtraFields
Class to manage standard extra fields.
Definition: extrafields.class.php:39
Product
Class to manage products or services.
Definition: product.class.php:46
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:53
price
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.
Definition: functions.lib.php:5829
Product\TYPE_SERVICE
const TYPE_SERVICE
Service.
Definition: product.class.php:577