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