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