dolibarr  17.0.4
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, 'bom_bom', '', '', 'rowid', $isdraft);
88 
89 // Permissions
90 $permissionnote = $user->rights->bom->write; // Used by the include of actions_setnotes.inc.php
91 $permissiondellink = $user->rights->bom->write; // Used by the include of actions_dellink.inc.php
92 $permissiontoadd = $user->rights->bom->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
93 $permissiontodelete = $user->rights->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  if ($qty == '') {
174  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
175  $error++;
176  }
177  if (!($idprod > 0)) {
178  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Product')), null, 'errors');
179  $error++;
180  }
181 
182  if ($object->fk_product == $idprod) {
183  setEventMessages($langs->trans('TheProductXIsAlreadyTheProductToProduce'), null, 'errors');
184  $error++;
185  }
186 
187  // We check if we're allowed to add this bom
188  $TParentBom=array();
189  $object->getParentBomTreeRecursive($TParentBom);
190  if ($bom_child_id > 0 && !empty($TParentBom) && in_array($bom_child_id, $TParentBom)) {
191  $n_child = new BOM($db);
192  $n_child->fetch($bom_child_id);
193  setEventMessages($langs->transnoentities('BomCantAddChildBom', $n_child->getNomUrl(1), $object->getNomUrl(1)), null, 'errors');
194  $error++;
195  }
196 
197  if (!$error) {
198  // Extrafields
199  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
200  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
201  // Unset extrafield
202  if (is_array($extralabelsline)) {
203  // Get extra fields
204  foreach ($extralabelsline as $key => $value) {
205  unset($_POST["options_".$key]);
206  }
207  }
208 
209  $result = $object->addLine($idprod, $qty, $qty_frozen, $disable_stock_change, $efficiency, -1, $bom_child_id, null, $fk_unit, $array_options);
210 
211  if ($result <= 0) {
212  setEventMessages($object->error, $object->errors, 'errors');
213  $action = '';
214  } else {
215  unset($_POST['idprod']);
216  unset($_POST['idprodservice']);
217  unset($_POST['qty']);
218  unset($_POST['qty_frozen']);
219  unset($_POST['disable_stock_change']);
220  }
221 
222  $object->fetchLines();
223 
224  $object->calculateCosts();
225  }
226  }
227 
228  // Update line
229  if ($action == 'updateline' && $user->rights->bom->write) {
230  $langs->load('errors');
231  $error = 0;
232 
233  // Set if we used free entry or predefined product
234  $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
235  $qty_frozen = price2num(GETPOST('qty_frozen', 'alpha'), 'MS');
236  $disable_stock_change = GETPOST('disable_stock_change', 'int');
237  $efficiency = price2num(GETPOST('efficiency', 'alpha'));
238  $fk_unit = GETPOST('fk_unit', 'alphanohtml');
239 
240  if ($qty == '') {
241  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
242  $error++;
243  }
244 
245  if (!$error) {
246  // Extrafields
247  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
248  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
249  // Unset extrafield
250  if (is_array($extralabelsline)) {
251  // Get extra fields
252  foreach ($extralabelsline as $key => $value) {
253  unset($_POST["options_".$key]);
254  }
255  }
256 
257  $bomline = new BOMLine($db);
258  $bomline->fetch($lineid);
259 
260  $result = $object->updateLine($lineid, $qty, (int) $qty_frozen, (int) $disable_stock_change, $efficiency, $bomline->position, $bomline->import_key, $fk_unit, $array_options);
261 
262  if ($result <= 0) {
263  setEventMessages($object->error, $object->errors, 'errors');
264  $action = '';
265  } else {
266  unset($_POST['idprod']);
267  unset($_POST['idprodservice']);
268  unset($_POST['qty']);
269  unset($_POST['qty_frozen']);
270  unset($_POST['disable_stock_change']);
271  }
272 
273  $object->fetchLines();
274 
275  $object->calculateCosts();
276  }
277  }
278 }
279 
280 
281 /*
282  * View
283  */
284 
285 $form = new Form($db);
286 $formfile = new FormFile($db);
287 
288 
289 $title = $langs->trans('BOM');
290 $help_url ='EN:Module_BOM';
291 llxHeader('', $title, $help_url);
292 
293 // Part to create
294 if ($action == 'create') {
295  print load_fiche_titre($langs->trans("NewBOM"), '', 'bom');
296 
297  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
298  print '<input type="hidden" name="token" value="'.newToken().'">';
299  print '<input type="hidden" name="action" value="add">';
300  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
301 
302  print dol_get_fiche_head(array(), '');
303 
304  print '<table class="border centpercent tableforfieldcreate">'."\n";
305 
306  // Common attributes
307  include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_add.tpl.php';
308 
309  // Other attributes
310  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
311 
312  print '</table>'."\n";
313 
314  print dol_get_fiche_end();
315 
316  print $form->buttonsSaveCancel("Create");
317 
318  print '</form>';
319 }
320 
321 // Part to edit record
322 if (($id || $ref) && $action == 'edit') {
323  print load_fiche_titre($langs->trans("BillOfMaterials"), '', 'cubes');
324 
325  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
326  print '<input type="hidden" name="token" value="'.newToken().'">';
327  print '<input type="hidden" name="action" value="update">';
328  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
329  print '<input type="hidden" name="id" value="'.$object->id.'">';
330 
331  print dol_get_fiche_head();
332 
333  //$object->fields['keyfield']['disabled'] = 1;
334 
335  print '<table class="border centpercent tableforfieldedit">'."\n";
336 
337  // Common attributes
338  include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_edit.tpl.php';
339 
340  // Other attributes
341  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_edit.tpl.php';
342 
343  print '</table>';
344 
345  print dol_get_fiche_end();
346 
347  print $form->buttonsSaveCancel("Create");
348 
349  print '</form>';
350 }
351 
352 // Part to show record
353 if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
354  $head = bomPrepareHead($object);
355  print dol_get_fiche_head($head, 'card', $langs->trans("BillOfMaterials"), -1, 'bom');
356 
357  $formconfirm = '';
358 
359  // Confirmation to delete
360  if ($action == 'delete') {
361  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteBillOfMaterials'), $langs->trans('ConfirmDeleteBillOfMaterials'), 'confirm_delete', '', 0, 1);
362  }
363  // Confirmation to delete line
364  if ($action == 'deleteline') {
365  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
366  }
367 
368  // Confirmation of validation
369  if ($action == 'validate') {
370  // We check that object has a temporary ref
371  $ref = substr($object->ref, 1, 4);
372  if ($ref == 'PROV') {
373  $object->fetch_product();
374  $numref = $object->getNextNumRef($object->product);
375  } else {
376  $numref = $object->ref;
377  }
378 
379  $text = $langs->trans('ConfirmValidateBom', $numref);
380  /*if (isModEnabled('notification'))
381  {
382  require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
383  $notify = new Notify($db);
384  $text .= '<br>';
385  $text .= $notify->confirmMessage('BOM_VALIDATE', $object->socid, $object);
386  }*/
387 
388  $formquestion = array();
389  if (isModEnabled('bom')) {
390  $langs->load("mrp");
391  $forcecombo = 0;
392  if ($conf->browser->name == 'ie') {
393  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
394  }
395  $formquestion = array(
396  // 'text' => $langs->trans("ConfirmClone"),
397  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
398  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
399  );
400  }
401 
402  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
403  }
404 
405  // Confirmation of closing
406  if ($action == 'close') {
407  $text = $langs->trans('ConfirmCloseBom', $object->ref);
408  /*if (isModEnabled('notification'))
409  {
410  require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
411  $notify = new Notify($db);
412  $text .= '<br>';
413  $text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
414  }*/
415 
416  $formquestion = array();
417  if (isModEnabled('bom')) {
418  $langs->load("mrp");
419  $forcecombo = 0;
420  if ($conf->browser->name == 'ie') {
421  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
422  }
423  $formquestion = array(
424  // 'text' => $langs->trans("ConfirmClone"),
425  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
426  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
427  );
428  }
429 
430  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
431  }
432 
433  // Confirmation of reopen
434  if ($action == 'reopen') {
435  $text = $langs->trans('ConfirmReopenBom', $object->ref);
436  /*if (isModEnabled('notification'))
437  {
438  require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
439  $notify = new Notify($db);
440  $text .= '<br>';
441  $text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
442  }*/
443 
444  $formquestion = array();
445  if (isModEnabled('bom')) {
446  $langs->load("mrp");
447  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
448  $forcecombo = 0;
449  if ($conf->browser->name == 'ie') {
450  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
451  }
452  $formquestion = array(
453  // 'text' => $langs->trans("ConfirmClone"),
454  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
455  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
456  );
457  }
458 
459  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $text, 'confirm_reopen', $formquestion, 0, 1, 220);
460  }
461 
462  // Clone confirmation
463  if ($action == 'clone') {
464  // Create an array for form
465  $formquestion = array();
466  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneBillOfMaterials', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
467  }
468 
469  // Confirmation of action xxxx
470  if ($action == 'setdraft') {
471  $text = $langs->trans('ConfirmSetToDraft', $object->ref);
472 
473  $formquestion = array();
474  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220);
475  }
476 
477  // Call Hook formConfirm
478  $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
479  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
480  if (empty($reshook)) {
481  $formconfirm .= $hookmanager->resPrint;
482  } elseif ($reshook > 0) {
483  $formconfirm = $hookmanager->resPrint;
484  }
485 
486  // Print form confirm
487  print $formconfirm;
488 
489 
490  // Object card
491  // ------------------------------------------------------------
492  $linkback = '<a href="'.DOL_URL_ROOT.'/bom/bom_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
493 
494  $morehtmlref = '<div class="refidno">';
495  /*
496  // Ref bis
497  $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', 0, 1);
498  $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', null, null, '', 1);
499  // Thirdparty
500  $morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1);
501  // Project
502  if (isModEnabled('project'))
503  {
504  $langs->load("projects");
505  $morehtmlref.='<br>'.$langs->trans('Project') . ' ';
506  if ($permissiontoadd)
507  {
508  if ($action != 'classify')
509  $morehtmlref.='<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token='.newToken().'&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> : ';
510  if ($action == 'classify') {
511  //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
512  $morehtmlref.='<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
513  $morehtmlref.='<input type="hidden" name="action" value="classin">';
514  $morehtmlref.='<input type="hidden" name="token" value="'.newToken().'">';
515  $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1);
516  $morehtmlref.='<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
517  $morehtmlref.='</form>';
518  } else {
519  $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
520  }
521  } else {
522  if (! empty($object->fk_project)) {
523  $proj = new Project($db);
524  $proj->fetch($object->fk_project);
525  $morehtmlref.=$proj->getNomUrl();
526  } else {
527  $morehtmlref.='';
528  }
529  }
530  }
531  */
532  $morehtmlref .= '</div>';
533 
534 
535  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
536 
537 
538  print '<div class="fichecenter">';
539  print '<div class="fichehalfleft">';
540  print '<div class="underbanner clearboth"></div>';
541  print '<table class="border centpercent tableforfield">'."\n";
542 
543  // Common attributes
544  $keyforbreak = 'duration';
545  include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
546  $object->calculateCosts();
547  print '<tr><td>'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).'</td><td><span class="amount">'.price($object->total_cost).'</span></td></tr>';
548  print '<tr><td>'.$langs->trans("UnitCost").'</td><td>'.price($object->unit_cost).'</td></tr>';
549 
550  // Other attributes
551  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
552 
553  print '</table>';
554  print '</div>';
555  print '</div>';
556 
557  print '<div class="clearboth"></div>';
558 
559  print dol_get_fiche_end();
560 
561 
562 
563  /*
564  * Lines
565  */
566 
567  if (!empty($object->table_element_line)) {
568  // Products
569  $res = $object->fetchLinesbytypeproduct(0); // Load all lines products into ->lines
570  $object->calculateCosts();
571 
572  print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product');
573 
574  print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '' : '') . '" method="POST">
575  <input type="hidden" name="token" value="' . newToken() . '">
576  <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
577  <input type="hidden" name="mode" value="">
578  <input type="hidden" name="page_y" value="">
579  <input type="hidden" name="id" value="' . $object->id . '">
580  ';
581 
582  if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
583  include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
584  }
585 
586  print '<div class="div-table-responsive-no-min">';
587  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
588  print '<table id="tablelines" class="noborder noshadow centpercent">';
589  }
590 
591  if (!empty($object->lines)) {
592  $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/bom/tpl');
593  }
594 
595  // Form to add new line
596  if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
597  if ($action != 'editline') {
598  // Add products/services form
599 
600 
601  $parameters = array();
602  $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
603  if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
604  if (empty($reshook))
605  $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
606  }
607  }
608 
609  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
610  print '</table>';
611  }
612  print '</div>';
613 
614  print "</form>\n";
615 
616  // Services
617  $filtertype = 1;
618  $res = $object->fetchLinesbytypeproduct(1); // Load all lines services into ->lines
619  $object->calculateCosts();
620 
621  print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service');
622 
623  print ' <form name="addservice" id="addservice" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '' : '') . '" method="POST">
624  <input type="hidden" name="token" value="' . newToken() . '">
625  <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
626  <input type="hidden" name="mode" value="">
627  <input type="hidden" name="page_y" value=""> <input type="hidden" name="id" value="' . $object->id . '">
628  ';
629 
630  if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
631  $tagidfortablednd = 'tablelinesservice';
632  include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
633  }
634 
635  print '<div class="div-table-responsive-no-min">';
636  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
637  print '<table id="tablelinesservice" class="noborder noshadow centpercent">';
638  }
639 
640  if (!empty($object->lines)) {
641  $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/bom/tpl');
642  }
643 
644  // Form to add new line
645  if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
646  if ($action != 'editline') {
647  // Add services form
648  $parameters = array();
649  $reshook = $hookmanager->executeHooks('formAddObjectServiceLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
650  if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
651  if (empty($reshook))
652  $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
653  }
654  }
655  }
656 
657  if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
658  print '</table>';
659  }
660  print '</div>';
661 
662  print "</form>\n";
663 
664 
666 
667 
668  $res = $object->fetchLines();
669 
670  // Buttons for actions
671 
672  if ($action != 'presend' && $action != 'editline') {
673  print '<div class="tabsAction">'."\n";
674  $parameters = array();
675  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
676  if ($reshook < 0) {
677  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
678  }
679 
680  if (empty($reshook)) {
681  // Send
682  //if (empty($user->socid)) {
683  // print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendMail') . '</a>'."\n";
684  //}
685 
686  // Back to draft
687  if ($object->status == $object::STATUS_VALIDATED) {
688  if ($permissiontoadd) {
689  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=setdraft&token='.newToken().'">'.$langs->trans("SetToDraft").'</a>'."\n";
690  }
691  }
692 
693  // Modify
694  if ($object->status == $object::STATUS_DRAFT) {
695  if ($permissiontoadd) {
696  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>'."\n";
697  } else {
698  print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\n";
699  }
700  }
701 
702  // Validate
703  if ($object->status == $object::STATUS_DRAFT) {
704  if ($permissiontoadd) {
705  if (is_array($object->lines) && count($object->lines) > 0) {
706  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&amp;action=validate&amp;token='.newToken().'">'.$langs->trans("Validate").'</a>'."\n";
707  } else {
708  $langs->load("errors");
709  print '<a class="butActionRefused" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>'."\n";
710  }
711  }
712  }
713 
714  // Re-open
715  if ($permissiontoadd && $object->status == $object::STATUS_CANCELED) {
716  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reopen&token='.newToken().'">'.$langs->trans("ReOpen").'</a>'."\n";
717  }
718 
719  // Create MO
720  if (isModEnabled('mrp')) {
721  if ($object->status == $object::STATUS_VALIDATED && !empty($user->rights->mrp->write)) {
722  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";
723  }
724  }
725 
726  // Clone
727  if ($permissiontoadd) {
728  print dolGetButtonAction($langs->trans("ToClone"), '', 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.(!empty($object->socid) ? '&socid='.$object->socid : "").'&action=clone&object=bom', 'clone', $permissiontoadd);
729  }
730 
731  // Close / Cancel
732  if ($permissiontoadd && $object->status == $object::STATUS_VALIDATED) {
733  print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
734  }
735 
736  /*
737  if ($user->rights->bom->write)
738  {
739  if ($object->status == 1)
740  {
741  print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=disable&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
742  }
743  else
744  {
745  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=enable&token='.newToken().'">'.$langs->trans("Enable").'</a>'."\n";
746  }
747  }
748  */
749 
750  // Delete
751  print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete);
752  }
753  print '</div>'."\n";
754  }
755 
756 
757  // Select mail models is same action as presend
758  if (GETPOST('modelselected')) {
759  $action = 'presend';
760  }
761 
762  if ($action != 'presend') {
763  print '<div class="fichecenter"><div class="fichehalfleft">';
764  print '<a name="builddoc"></a>'; // ancre
765 
766  // Documents
767  $objref = dol_sanitizeFileName($object->ref);
768  $relativepath = $objref.'/'.$objref.'.pdf';
769  $filedir = $conf->bom->dir_output.'/'.$objref;
770  $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
771  $genallowed = $user->rights->bom->read; // If you can read, you can build the PDF to read content
772  $delallowed = $user->rights->bom->write; // If you can create/edit, you can remove a file on card
773  print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang);
774 
775  // Show links to link elements
776  $linktoelem = $form->showLinkToObjectBlock($object, null, array('bom'));
777  $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
778 
779 
780  print '</div><div class="fichehalfright">';
781 
782  $MAXEVENT = 10;
783 
784  $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/bom/bom_agenda.php?id='.$object->id);
785 
786  // List of actions on element
787  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
788  $formactions = new FormActions($db);
789  $somethingshown = $formactions->showactions($object, $object->element, 0, 1, '', $MAXEVENT, '', $morehtmlcenter);
790 
791  print '</div></div>';
792  }
793 
794  //Select mail models is same action as presend
795  if (GETPOST('modelselected')) {
796  $action = 'presend';
797  }
798 
799  // Presend form
800  $modelmail = 'bom';
801  $defaulttopic = 'InformationMessage';
802  $diroutput = $conf->bom->dir_output;
803  $trackid = 'bom'.$object->id;
804 
805  include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
806 }
807 
808 
809 // End of page
810 llxFooter();
811 $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:37
Class for BOMLine.
Definition: bom.class.php:1545
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.
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='')
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.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
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.
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.