dolibarr 24.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-2026 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';
39require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
40require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
41require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
42require_once DOL_DOCUMENT_ROOT.'/bom/lib/bom.lib.php';
43require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp.lib.php';
44
45
46// Load translation files required by the page
47$langs->loadLangs(array('mrp', 'other'));
48
49// Get parameters
50$id = GETPOSTINT('id');
51$lineid = GETPOSTINT('lineid');
52$ref = GETPOST('ref', 'alpha');
53$action = GETPOST('action', 'aZ09');
54$confirm = GETPOST('confirm', 'alpha');
55$cancel = GETPOST('cancel', 'alpha');
56$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'bomcard'; // To manage different context of search
57$backtopage = GETPOST('backtopage', 'alpha');
58
59
60// PDF
61$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
62$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
63$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
64
65// Initialize a technical objects
66$object = new BOM($db);
67$diroutputmassaction = getMultidirOutput($object) . '/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 = $object->TRIGGER_PREFIX.'_MODIFY'; // Name of trigger action code to execute when we modify record. Used in actions_addupdatedelete.inc.php
134
135 // Actions cancel, add, update, delete or clone
136 include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
137
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) { // Test on permission not required
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 = $object->TRIGGER_PREFIX.'_SENTBYMAIL';
157 $autocopy = 'MAIN_MAIL_AUTOCOPY_'.$object->TRIGGER_PREFIX.'_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 $idprod = 0;
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 = GETPOSTINT('qty_frozen');
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 = GETPOSTINT('qty_frozen');
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, $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 = (string) $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="'.dolBuildUrl($_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="'.dolBuildUrl($_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, $object->picto, 0, '', '', 0, '', 1);
394
395 $formconfirm = '';
396
397 // Confirmation to delete
398 if ($action == 'delete') {
399 $formconfirm = $form->formconfirm(dolBuildUrl($_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(dolBuildUrl($_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 $error = 0;
409 $numref = '';
410 // We check that object has a temporary ref
411 $ref = substr($object->ref, 1, 4);
412 if ($ref == 'PROV') {
413 $res = $object->fetch_product();
414 if ($res > 0 && $object->product instanceof Product) {
415 $numref = $object->getNextNumRef($object->product); // @phan-suppress-current-line PhanTypeMismatchArgumentNullable
416 } else {
417 $error++;
418 }
419 } else {
420 $numref = (string) $object->ref;
421 }
422
423 $text = $langs->trans('ConfirmValidateBom', $numref);
424 /*if (isModEnabled('notification')) {
425 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
426 $notify = new Notify($db);
427 $text .= '<br>';
428 $text .= $notify->confirmMessage('BOM_VALIDATE', $object->socid, $object);
429 }*/
430
431 $formquestion = array();
432 if (isModEnabled('bom')) {
433 $langs->load("mrp");
434 $formquestion = array(
435 // 'text' => $langs->trans("ConfirmClone"),
436 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
437 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
438 );
439 }
440 if (!$error) {
441 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
442 } else {
443 setEventMessage($langs->trans('Error'), 'errors');
444 $action = '';
445 }
446 }
447
448 // Confirmation of closing
449 if ($action == 'close') {
450 $text = $langs->trans('ConfirmCloseBom', $object->ref);
451 /*if (isModEnabled('notification')) {
452 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
453 $notify = new Notify($db);
454 $text .= '<br>';
455 $text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
456 }*/
457
458 $formquestion = array();
459 if (isModEnabled('bom')) {
460 $langs->load("mrp");
461 $formquestion = array(
462 // 'text' => $langs->trans("ConfirmClone"),
463 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
464 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
465 );
466 }
467
468 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
469 }
470
471 // Confirmation of reopen
472 if ($action == 'reopen') {
473 $text = $langs->trans('ConfirmReopenBom', $object->ref);
474 /*if (isModEnabled('notification')) {
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 $formquestion = array(
486 // 'text' => $langs->trans("ConfirmClone"),
487 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
488 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
489 );
490 }
491
492 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ReOpen'), $text, 'confirm_reopen', $formquestion, 0, 1, 220);
493 }
494
495 // Clone confirmation
496 if ($action == 'clone') {
497 // Create an array for form
498 $formquestion = array();
499 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ToClone'), $langs->trans('ConfirmCloneBillOfMaterials', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
500 }
501
502 // Confirmation of action setdraft
503 if ($action == 'setdraft') {
504 $text = $langs->trans('ConfirmSetToDraft', $object->ref);
505
506 $formquestion = array();
507 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220);
508 }
509
510 // Call Hook formConfirm
511 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
512 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
513 if (empty($reshook)) {
514 $formconfirm .= $hookmanager->resPrint;
515 } elseif ($reshook > 0) {
516 $formconfirm = $hookmanager->resPrint;
517 }
518
519 // Print form confirm
520 print $formconfirm;
521
522
523 // Object card
524 // ------------------------------------------------------------
525 $linkback = '<a href="'.DOL_URL_ROOT.'/bom/bom_list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
526
527 $morehtmlref = '<div class="refidno">';
528 /*
529 // Ref bis
530 $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->hasRight('bom', 'creer'), 'string', '', 0, 1);
531 $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->hasRight('bom', 'creer'), 'string', '', null, null, '', 1);
532 // Thirdparty
533 $morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1);
534 // Project
535 if (isModEnabled('project')) {
536 $langs->load("projects");
537 $morehtmlref.='<br>'.$langs->trans('Project') . ' ';
538 if ($permissiontoadd) {
539 if ($action != 'classify')
540 $morehtmlref.='<a class="editfielda" href="' . dolBuildUrl($_SERVER['PHP_SELF'], ['action' => 'classify', 'id' => $object->id], true) . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> : ';
541 if ($action == 'classify') {
542 //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
543 $morehtmlref.='<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
544 $morehtmlref.='<input type="hidden" name="action" value="classin">';
545 $morehtmlref.='<input type="hidden" name="token" value="'.newToken().'">';
546 $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1);
547 $morehtmlref.='<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
548 $morehtmlref.='</form>';
549 } else {
550 $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
551 }
552 } else {
553 if (! empty($object->fk_project)) {
554 $proj = new Project($db);
555 $proj->fetch($object->fk_project);
556 $morehtmlref.=$proj->getNomUrl();
557 } else {
558 $morehtmlref.='';
559 }
560 }
561 }
562 */
563 $morehtmlref .= '</div>';
564
565
566 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
567
568
569 print '<div class="fichecenter">';
570 print '<div class="fichehalfleft">';
571 print '<div class="underbanner clearboth"></div>';
572 print '<table class="border centpercent tableforfield">'."\n";
573
574 // Common attributes
575 $keyforbreak = 'duration';
576 include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
577
578 // Manufacturing cost
579 print '<tr><td>'.$form->textwithpicto($langs->trans("ManufacturingCost"), $langs->trans("BOMTotalCost")).'</td><td><span class="amount">';
580 print price($object->total_cost);
581 print '</span>';
582 if ($object->total_cost != $object->unit_cost) {
583 print '&nbsp; &nbsp; <span class="opacitymedium">('.$form->textwithpicto(price($object->unit_cost), $langs->trans("ManufacturingUnitCost"), 1, 'help', '').')</span>';
584 }
585 print '</td></tr>';
586
587 // Find sell price of generated product. We suppose we sell it to a company like ours (same country...).
588 $object->fetch_product();
589 $manufacturedvalued = '';
590 if (!empty($object->product)) {
591 $tmparray = $object->product->getSellPrice($mysoc, $mysoc);
592 $manufacturedvalued = $tmparray['pu_ht'] * $object->qty;
593 }
594 print '<tr><td>'.$langs->trans("ManufacturingGeneratedValue").'</td><td><span class="amount">'.price($manufacturedvalued).'</span></td></tr>';
595
596 // Other attributes
597 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
598
599 print '</table>';
600 print '</div>';
601 print '</div>';
602
603 print '<div class="clearboth"></div>';
604
605 print dol_get_fiche_end();
606
607
608
609 /*
610 * Lines
611 */
612
613 if (!empty($object->table_element_line)) {
614 // Products
615
616 $res = $object->fetchLinesbytypeproduct(0); // Load all lines products into ->lines
617 $object->calculateCosts();
618
619 print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product');
620
621 print ' <form name="addproduct" id="listbomproducts" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="POST">
622 <input type="hidden" name="token" value="' . newToken() . '">
623 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
624 <input type="hidden" name="mode" value="">
625 <input type="hidden" name="page_y" value="">
626 <input type="hidden" name="id" value="' . $object->id . '">
627 ';
628
629 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
630 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
631 }
632
633 print '<div class="div-table-responsive-no-min">';
634 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
635 print '<table id="tablelines" class="noborder noshadow centpercent">';
636 }
637
638 if (!empty($object->lines)) {
639 $object->printObjectLines($action, $mysoc, null, GETPOSTINT('lineid'), 1, '/bom/tpl');
640 }
641
642 // Form to add new line
643 if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
644 if ($action != 'editline') {
645 // Add products/services form
646
647
648 $parameters = array();
649 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
650 if ($reshook < 0) {
651 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
652 }
653 if (empty($reshook)) {
654 $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
655 }
656 }
657 }
658
659 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
660 print '</table>';
661 }
662 print '</div>';
663
664 print "</form>\n";
665
666
667 // Services
668
669 $filtertype = 1;
670 $res = $object->fetchLinesbytypeproduct($filtertype); // Load all lines services into ->lines
671 $object->calculateCosts();
672
673 print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service');
674
675 print ' <form name="addservice" id="listbomservices" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="POST">
676 <input type="hidden" name="token" value="' . newToken() . '">
677 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
678 <input type="hidden" name="mode" value="">
679 <input type="hidden" name="page_y" value=""> <input type="hidden" name="id" value="' . $object->id . '">
680 ';
681
682 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
683 $tagidfortablednd = 'tablelinesservice';
684 include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
685 }
686
687 print '<div class="div-table-responsive-no-min">';
688 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
689 print '<table id="tablelinesservice" class="noborder noshadow centpercent">';
690 }
691
692 if (!empty($object->lines)) {
693 $object->printObjectLines($action, $mysoc, null, GETPOSTINT('lineid'), 1, '/bom/tpl');
694 }
695
696 // Form to add new line
697 if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
698 if ($action != 'editline') {
699 // Add services form
700 $parameters = array();
701 $reshook = $hookmanager->executeHooks('formAddObjectServiceLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
702 if ($reshook < 0) {
703 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
704 }
705 if (empty($reshook)) {
706 $object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
707 }
708 }
709 }
710 }
711
712 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
713 print '</table>';
714 }
715 print '</div>';
716
717 print "</form>\n";
718
719
721
722
723 $res = $object->fetchLines();
724
725 // Buttons for actions
726
727 if ($action != 'presend' && $action != 'editline') {
728 print '<div class="tabsAction">'."\n";
729 $parameters = array();
730 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
731 if ($reshook < 0) {
732 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
733 }
734
735 if (empty($reshook)) {
736 // Send
737 //if (empty($user->socid)) {
738 // print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendMail') . '</a>'."\n";
739 //}
740
741 // Back to draft
742 if ($object->status == $object::STATUS_VALIDATED) {
743 if ($permissiontoadd) {
744 print '<a class="butAction" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['id' => $object->id, 'action' => 'setdraft'], true).'">'.$langs->trans("SetToDraft").'</a>'."\n";
745 }
746 }
747
748 // Modify
749 if ($object->status == $object::STATUS_DRAFT) {
750 if ($permissiontoadd) {
751 print '<a class="butAction" href="'.dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id, 'action' => 'edit'], true).'">'.$langs->trans("Modify").'</a>'."\n";
752 } else {
753 print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\n";
754 }
755 }
756
757 // Validate
758 if ($object->status == $object::STATUS_DRAFT) {
759 if ($permissiontoadd) {
760 if (is_array($object->lines) && count($object->lines) > 0) {
761 print '<a class="butAction" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['id' => $object->id, 'action' => 'validate'], true).'">'.$langs->trans("Validate").'</a>'."\n";
762 } else {
763 $langs->load("errors");
764 print '<a class="butActionRefused classfortooltip" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>'."\n";
765 }
766 }
767 }
768
769 // Re-open
770 if ($permissiontoadd && $object->status == $object::STATUS_CANCELED) {
771 print '<a class="butAction" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['id' => $object->id, 'action' => 'reopen'], true).'">'.$langs->trans("ReOpen").'</a>'."\n";
772 }
773
774 // Create MO
775 if (isModEnabled('mrp')) {
776 if ($object->status == $object::STATUS_VALIDATED && $user->hasRight('mrp', 'write')) {
777 print '<a class="butAction" href="'.dolBuildUrl(DOL_URL_ROOT.'/mrp/mo_card.php', ['action' => 'create', 'fk_bom' => $object->id], true).'&backtopageforcancel='.urlencode(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id])).'">'.$langs->trans("CreateMO").'</a>'."\n";
778 }
779 }
780
781 // Clone
782 if ($permissiontoadd) {
783 print dolGetButtonAction($langs->trans("ToClone"), '', 'clone', dolBuildUrl($_SERVER['PHP_SELF'], ['id' => $object->id, 'action' => 'clone', 'object' => 'bom'], true), 'clone', $permissiontoadd);
784 }
785
786 // Close / Cancel
787 if ($permissiontoadd && $object->status == $object::STATUS_VALIDATED) {
788 print '<a class="butActionDelete" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['id' => $object->id, 'action' => 'close'], true).'">'.$langs->trans("Disable").'</a>'."\n";
789 }
790
791 /*
792 if ($user->hasRight('bom', 'write')) {
793 if ($object->status == 1) {
794 print '<a class="butActionDelete" href="'.dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id, 'action' => 'disenable'], true).'">'.$langs->trans("Disable").'</a>'."\n";
795 } else {
796 print '<a class="butAction" href="'.dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id, 'action' => 'enable'], true).'">'.$langs->trans("Enable").'</a>'."\n";
797 }
798 }
799 */
800
801 // Delete
802 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id, 'action' => 'delete'], true), 'delete', $permissiontodelete);
803 }
804 print '</div>'."\n";
805 }
806
807
808 // Select mail models is same action as presend
809 if (GETPOST('modelselected')) {
810 $action = 'presend';
811 }
812
813 if ($action != 'presend') {
814 print '<div class="fichecenter"><div class="fichehalfleft">';
815 print '<a name="builddoc"></a>'; // ancre
816
817 // Documents
818 $objref = dol_sanitizeFileName($object->ref);
819 $relativepath = $objref.'/'.$objref.'.pdf';
820 $filedir = getMultidirOutput($object) . '/'.$objref;
821 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
822 $genallowed = $user->hasRight('bom', 'read'); // If you can read, you can build the PDF to read content
823 $delallowed = $user->hasRight('bom', 'write'); // If you can create/edit, you can remove a file on card
824 print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang, '', $object);
825
826 // Show links to link elements
827 $tmparray = $form->showLinkToObjectBlock($object, array(), array('bom'), 1);
828 $linktoelem = $tmparray['linktoelem'];
829 $htmltoenteralink = $tmparray['htmltoenteralink'];
830 print $htmltoenteralink;
831
832 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
833
834
835 print '</div><div class="fichehalfright">';
836
837 $MAXEVENT = 10;
838
839 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/bom/bom_agenda.php?id='.$object->id);
840
841 // List of actions on element
842 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
843 $formactions = new FormActions($db);
844 $somethingshown = $formactions->showactions($object, $object->element, 0, 1, '', $MAXEVENT, '', $morehtmlcenter);
845
846 print '</div></div>';
847 }
848
849 //Select mail models is same action as presend
850 if (GETPOST('modelselected')) {
851 $action = 'presend';
852 }
853
854 // Presend form
855 $modelmail = 'bom';
856 $defaulttopic = 'InformationMessage';
857 $diroutput = getMultidirOutput($object);
858 $trackid = 'bom'.$object->id;
859
860 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
861}
862
863
864// End of page
865llxFooter();
866$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
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:164
bomPrepareHead($object)
Prepare array of tabs for BillOfMaterials.
Definition bom.lib.php:90
Class for BOM.
Definition bom.class.php:42
Class for BOMLine.
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.
global $mysoc
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
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 '.
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0, $attop=0)
Set event message in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
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.
getMultidirOutput($object, $module='', $forobject=0, $mode='output')
Return the full path of the directory where a module (or an object of a module) stores its files.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
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.