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