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 $formquestion = array(
429 // 'text' => $langs->trans("ConfirmClone"),
430 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
431 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
432 );
433 }
434
435 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
436 }
437
438 // Confirmation of closing
439 if ($action == 'close') {
440 $text = $langs->trans('ConfirmCloseBom', $object->ref);
441 /*if (isModEnabled('notification'))
442 {
443 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
444 $notify = new Notify($db);
445 $text .= '<br>';
446 $text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
447 }*/
448
449 $formquestion = array();
450 if (isModEnabled('bom')) {
451 $langs->load("mrp");
452 $formquestion = array(
453 // 'text' => $langs->trans("ConfirmClone"),
454 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
455 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
456 );
457 }
458
459 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
460 }
461
462 // Confirmation of reopen
463 if ($action == 'reopen') {
464 $text = $langs->trans('ConfirmReopenBom', $object->ref);
465 /*if (isModEnabled('notification'))
466 {
467 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
468 $notify = new Notify($db);
469 $text .= '<br>';
470 $text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
471 }*/
472
473 $formquestion = array();
474 if (isModEnabled('bom')) {
475 $langs->load("mrp");
476 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
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
572 // Manufacturing cost
573 print '<tr><td>'.$form->textwithpicto($langs->trans("ManufacturingCost"), $langs->trans("BOMTotalCost")).'</td><td><span class="amount">';
574 print price($object->total_cost);
575 print '</span>';
576 if ($object->total_cost != $object->unit_cost) {
577 print '&nbsp; &nbsp; <span class="opacitymedium">('.$form->textwithpicto(price($object->unit_cost), $langs->trans("ManufacturingUnitCost"), 1, 'help', '').')</span>';
578 }
579 print '</td></tr>';
580
581 // Find sell price of generated product. We suppose we sell it to a company like ours (same country...).
582 $object->fetch_product();
583 $manufacturedvalued = '';
584 if (!empty($object->product)) {
585 $tmparray = $object->product->getSellPrice($mysoc, $mysoc);
586 $manufacturedvalued = $tmparray['pu_ht'] * $object->qty;
587 }
588 print '<tr><td>'.$langs->trans("ManufacturingGeneratedValue").'</td><td><span class="amount">'.price($manufacturedvalued).'</span></td></tr>';
589
590 // Other attributes
591 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
592
593 print '</table>';
594 print '</div>';
595 print '</div>';
596
597 print '<div class="clearboth"></div>';
598
599 print dol_get_fiche_end();
600
601
602
603 /*
604 * Lines
605 */
606
607 if (!empty($object->table_element_line)) {
608 // Products
609
610 $res = $object->fetchLinesbytypeproduct(0); // Load all lines products into ->lines
611 $object->calculateCosts();
612
613 print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product');
614
615 print ' <form name="addproduct" id="listbomproducts" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="POST">
616 <input type="hidden" name="token" value="' . newToken() . '">
617 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
618 <input type="hidden" name="mode" value="">
619 <input type="hidden" name="page_y" value="">
620 <input type="hidden" name="id" value="' . $object->id . '">
621 ';
622
623 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
624 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
625 }
626
627 print '<div class="div-table-responsive-no-min">';
628 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
629 print '<table id="tablelines" class="noborder noshadow centpercent">';
630 }
631
632 if (!empty($object->lines)) {
633 $object->printObjectLines($action, $mysoc, null, GETPOSTINT('lineid'), 1, '/bom/tpl');
634 }
635
636 // Form to add new line
637 if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
638 if ($action != 'editline') {
639 // Add products/services form
640
641
642 $parameters = array();
643 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
644 if ($reshook < 0) {
645 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
646 }
647 if (empty($reshook)) {
648 $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
649 }
650 }
651 }
652
653 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
654 print '</table>';
655 }
656 print '</div>';
657
658 print "</form>\n";
659
660
661 // Services
662
663 $filtertype = 1;
664 $res = $object->fetchLinesbytypeproduct($filtertype); // Load all lines services into ->lines
665 $object->calculateCosts();
666
667 print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service');
668
669 print ' <form name="addservice" id="listbomservices" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="POST">
670 <input type="hidden" name="token" value="' . newToken() . '">
671 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
672 <input type="hidden" name="mode" value="">
673 <input type="hidden" name="page_y" value=""> <input type="hidden" name="id" value="' . $object->id . '">
674 ';
675
676 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
677 $tagidfortablednd = 'tablelinesservice';
678 include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
679 }
680
681 print '<div class="div-table-responsive-no-min">';
682 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
683 print '<table id="tablelinesservice" class="noborder noshadow centpercent">';
684 }
685
686 if (!empty($object->lines)) {
687 $object->printObjectLines($action, $mysoc, null, GETPOSTINT('lineid'), 1, '/bom/tpl');
688 }
689
690 // Form to add new line
691 if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
692 if ($action != 'editline') {
693 // Add services form
694 $parameters = array();
695 $reshook = $hookmanager->executeHooks('formAddObjectServiceLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
696 if ($reshook < 0) {
697 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
698 }
699 if (empty($reshook)) {
700 $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
701 }
702 }
703 }
704 }
705
706 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
707 print '</table>';
708 }
709 print '</div>';
710
711 print "</form>\n";
712
713
715
716
717 $res = $object->fetchLines();
718
719 // Buttons for actions
720
721 if ($action != 'presend' && $action != 'editline') {
722 print '<div class="tabsAction">'."\n";
723 $parameters = array();
724 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
725 if ($reshook < 0) {
726 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
727 }
728
729 if (empty($reshook)) {
730 // Send
731 //if (empty($user->socid)) {
732 // print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendMail') . '</a>'."\n";
733 //}
734
735 // Back to draft
736 if ($object->status == $object::STATUS_VALIDATED) {
737 if ($permissiontoadd) {
738 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=setdraft&token='.newToken().'">'.$langs->trans("SetToDraft").'</a>'."\n";
739 }
740 }
741
742 // Modify
743 if ($object->status == $object::STATUS_DRAFT) {
744 if ($permissiontoadd) {
745 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>'."\n";
746 } else {
747 print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\n";
748 }
749 }
750
751 // Validate
752 if ($object->status == $object::STATUS_DRAFT) {
753 if ($permissiontoadd) {
754 if (is_array($object->lines) && count($object->lines) > 0) {
755 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&amp;action=validate&amp;token='.newToken().'">'.$langs->trans("Validate").'</a>'."\n";
756 } else {
757 $langs->load("errors");
758 print '<a class="butActionRefused classfortooltip" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>'."\n";
759 }
760 }
761 }
762
763 // Re-open
764 if ($permissiontoadd && $object->status == $object::STATUS_CANCELED) {
765 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reopen&token='.newToken().'">'.$langs->trans("ReOpen").'</a>'."\n";
766 }
767
768 // Create MO
769 if (isModEnabled('mrp')) {
770 if ($object->status == $object::STATUS_VALIDATED && $user->hasRight('mrp', 'write')) {
771 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";
772 }
773 }
774
775 // Clone
776 if ($permissiontoadd) {
777 print dolGetButtonAction($langs->trans("ToClone"), '', 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.(!empty($object->socid) ? '&socid='.$object->socid : "").'&action=clone&object=bom', 'clone', $permissiontoadd);
778 }
779
780 // Close / Cancel
781 if ($permissiontoadd && $object->status == $object::STATUS_VALIDATED) {
782 print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
783 }
784
785 /*
786 if ($user->hasRight('bom', 'write')) {
787 if ($object->status == 1) {
788 print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=disable&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
789 } else {
790 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=enable&token='.newToken().'">'.$langs->trans("Enable").'</a>'."\n";
791 }
792 }
793 */
794
795 // Delete
796 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete);
797 }
798 print '</div>'."\n";
799 }
800
801
802 // Select mail models is same action as presend
803 if (GETPOST('modelselected')) {
804 $action = 'presend';
805 }
806
807 if ($action != 'presend') {
808 print '<div class="fichecenter"><div class="fichehalfleft">';
809 print '<a name="builddoc"></a>'; // ancre
810
811 // Documents
812 $objref = dol_sanitizeFileName($object->ref);
813 $relativepath = $objref.'/'.$objref.'.pdf';
814 $filedir = $conf->bom->dir_output.'/'.$objref;
815 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
816 $genallowed = $user->hasRight('bom', 'read'); // If you can read, you can build the PDF to read content
817 $delallowed = $user->hasRight('bom', 'write'); // If you can create/edit, you can remove a file on card
818 print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang);
819
820 // Show links to link elements
821 $tmparray = $form->showLinkToObjectBlock($object, array(), array('bom'), 1);
822 $linktoelem = $tmparray['linktoelem'];
823 $htmltoenteralink = $tmparray['htmltoenteralink'];
824 print $htmltoenteralink;
825
826 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
827
828
829 print '</div><div class="fichehalfright">';
830
831 $MAXEVENT = 10;
832
833 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/bom/bom_agenda.php?id='.$object->id);
834
835 // List of actions on element
836 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
837 $formactions = new FormActions($db);
838 $somethingshown = $formactions->showactions($object, $object->element, 0, 1, '', $MAXEVENT, '', $morehtmlcenter);
839
840 print '</div></div>';
841 }
842
843 //Select mail models is same action as presend
844 if (GETPOST('modelselected')) {
845 $action = 'presend';
846 }
847
848 // Presend form
849 $modelmail = 'bom';
850 $defaulttopic = 'InformationMessage';
851 $diroutput = $conf->bom->dir_output;
852 $trackid = 'bom'.$object->id;
853
854 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
855}
856
857
858// End of page
859llxFooter();
860$db->close();
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:87
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.
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.