26 require
'../main.inc.php';
27 require_once DOL_DOCUMENT_ROOT.
'/core/class/html.formcompany.class.php';
28 require_once DOL_DOCUMENT_ROOT.
'/core/class/html.formfile.class.php';
29 require_once DOL_DOCUMENT_ROOT.
'/bom/class/bom.class.php';
30 require_once DOL_DOCUMENT_ROOT.
'/bom/lib/bom.lib.php';
31 require_once DOL_DOCUMENT_ROOT.
'/mrp/lib/mrp.lib.php';
35 $langs->loadLangs(array(
'mrp',
'other'));
39 $lineid =
GETPOST(
'lineid',
'int');
41 $action =
GETPOST(
'action',
'aZ09');
42 $confirm =
GETPOST(
'confirm',
'alpha');
43 $cancel =
GETPOST(
'cancel',
'aZ09');
44 $contextpage =
GETPOST(
'contextpage',
'aZ') ?
GETPOST(
'contextpage',
'aZ') :
'bomcard';
45 $backtopage =
GETPOST(
'backtopage',
'alpha');
49 $hidedetails = (
GETPOST(
'hidedetails',
'int') ?
GETPOST(
'hidedetails',
'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0));
50 $hidedesc = (
GETPOST(
'hidedesc',
'int') ?
GETPOST(
'hidedesc',
'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0));
51 $hideref = (
GETPOST(
'hideref',
'int') ?
GETPOST(
'hideref',
'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
54 $object =
new BOM($db);
56 $diroutputmassaction = $conf->bom->dir_output.
'/temp/massgeneration/'.$user->id;
57 $hookmanager->initHooks(array(
'bomcard',
'globalcard'));
60 $extrafields->fetch_name_optionals_label($object->table_element);
61 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element,
'',
'search_');
64 $search_all =
GETPOST(
"search_all",
'alpha');
66 foreach ($object->fields as $key => $val) {
67 if (
GETPOST(
'search_'.$key,
'alpha')) {
68 $search[$key] =
GETPOST(
'search_'.$key,
'alpha');
72 if (empty($action) && empty($id) && empty($ref)) {
77 include DOL_DOCUMENT_ROOT.
'/core/actions_fetchobject.inc.php';
78 if ($object->id > 0) {
79 $object->calculateCosts();
86 $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
87 $result =
restrictedArea($user,
'bom', $object->id, $object->table_element,
'',
'',
'rowid', $isdraft);
90 $permissionnote = $user->hasRight(
'bom',
'write');
91 $permissiondellink = $user->hasRight(
'bom',
'write');
92 $permissiontoadd = $user->hasRight(
'bom',
'write');
93 $permissiontodelete = $user->hasRight(
'bom',
'delete') || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT);
94 $upload_dir = $conf->bom->multidir_output[isset($object->entity) ? $object->entity : 1];
101 $parameters = array();
102 $reshook = $hookmanager->executeHooks(
'doActions', $parameters, $object, $action);
107 if (empty($reshook)) {
110 $backurlforlist = DOL_URL_ROOT.
'/bom/bom_list.php';
112 if (empty($backtopage) || ($cancel && empty($id))) {
113 if (empty($backtopage) || ($cancel && strpos($backtopage,
'__ID__'))) {
114 if (empty($id) && (($action !=
'add' && $action !=
'create') || $cancel)) {
115 $backtopage = $backurlforlist;
117 $backtopage = DOL_URL_ROOT.
'/bom/bom_card.php?id='.($id > 0 ? $id :
'__ID__');
122 $triggermodname =
'BOM_MODIFY';
126 include DOL_DOCUMENT_ROOT.
'/core/actions_addupdatedelete.inc.php';
128 if ($action ==
'confirm_validate' && $object->id > 0) {
129 $object->calculateCosts();
133 include DOL_DOCUMENT_ROOT.
'/core/actions_dellink.inc.php';
136 include DOL_DOCUMENT_ROOT.
'/core/actions_printing.inc.php';
142 include DOL_DOCUMENT_ROOT.
'/core/actions_builddoc.inc.php';
145 $triggersendname =
'BOM_SENTBYMAIL';
146 $autocopy =
'MAIN_MAIL_AUTOCOPY_BOM_TO';
147 $trackid =
'bom'.$object->id;
148 include DOL_DOCUMENT_ROOT.
'/core/actions_sendmails.inc.php';
151 if ($action ==
'addline' && $user->rights->bom->write) {
152 $langs->load(
'errors');
157 $bom_child_id = (int)
GETPOST(
'bom_id',
'int');
158 if ($bom_child_id > 0) {
159 $bom_child =
new BOM($db);
160 $res = $bom_child->fetch($bom_child_id);
162 $idprod = $bom_child->fk_product;
165 $idprod = (!empty(
GETPOST(
'idprodservice',
'int')) ?
GETPOST(
'idprodservice',
'int') : (int)
GETPOST(
'idprod',
'int'));
170 $disable_stock_change =
GETPOST(
'disable_stock_change',
'int');
172 $fk_unit =
GETPOST(
'fk_unit',
'alphanohtml');
174 if (!empty($idprod) && $conf->workstation->enabled) {
176 $res = $product->fetch($idprod);
177 if ($res > 0 && $product->type ==
Product::TYPE_SERVICE) $fk_default_workstation = $product->fk_default_workstation;
181 setEventMessages($langs->trans(
'ErrorFieldRequired', $langs->transnoentitiesnoconv(
'Qty')),
null,
'errors');
184 if (!($idprod > 0)) {
185 setEventMessages($langs->trans(
'ErrorFieldRequired', $langs->transnoentitiesnoconv(
'Product')),
null,
'errors');
189 if ($object->fk_product == $idprod) {
190 setEventMessages($langs->trans(
'TheProductXIsAlreadyTheProductToProduce'),
null,
'errors');
196 $object->getParentBomTreeRecursive($TParentBom);
197 if ($bom_child_id > 0 && !empty($TParentBom) && in_array($bom_child_id, $TParentBom)) {
198 $n_child =
new BOM($db);
199 $n_child->fetch($bom_child_id);
200 setEventMessages($langs->transnoentities(
'BomCantAddChildBom', $n_child->getNomUrl(1), $object->getNomUrl(1)),
null,
'errors');
206 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
207 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
209 if (is_array($extralabelsline)) {
211 foreach ($extralabelsline as $key => $value) {
212 unset($_POST[
"options_".$key]);
216 $result = $object->addLine($idprod, $qty, $qty_frozen, $disable_stock_change, $efficiency, -1, $bom_child_id,
null, $fk_unit, $array_options, $fk_default_workstation);
222 unset($_POST[
'idprod']);
223 unset($_POST[
'idprodservice']);
224 unset($_POST[
'qty']);
225 unset($_POST[
'qty_frozen']);
226 unset($_POST[
'disable_stock_change']);
229 $object->fetchLines();
231 $object->calculateCosts();
236 if ($action ==
'updateline' && $user->rights->bom->write) {
237 $langs->load(
'errors');
243 $disable_stock_change =
GETPOST(
'disable_stock_change',
'int');
245 $fk_unit =
GETPOST(
'fk_unit',
'alphanohtml');
248 setEventMessages($langs->trans(
'ErrorFieldRequired', $langs->transnoentitiesnoconv(
'Qty')),
null,
'errors');
254 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
255 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
257 if (is_array($extralabelsline)) {
259 foreach ($extralabelsline as $key => $value) {
260 unset($_POST[
"options_".$key]);
265 $bomline->fetch($lineid);
267 $result = $object->updateLine($lineid, $qty, (
int) $qty_frozen, (
int) $disable_stock_change, $efficiency, $bomline->position, $bomline->import_key, $fk_unit, $array_options);
273 unset($_POST[
'idprod']);
274 unset($_POST[
'idprodservice']);
275 unset($_POST[
'qty']);
276 unset($_POST[
'qty_frozen']);
277 unset($_POST[
'disable_stock_change']);
280 $object->fetchLines();
282 $object->calculateCosts();
296 $title = $langs->trans(
'BOM');
301 if ($action ==
'create') {
304 print
'<form method="POST" action="'.$_SERVER[
"PHP_SELF"].
'">';
305 print
'<input type="hidden" name="token" value="'.newToken().
'">';
306 print
'<input type="hidden" name="action" value="add">';
307 print
'<input type="hidden" name="backtopage" value="'.$backtopage.
'">';
311 print
'<table class="border centpercent tableforfieldcreate">'.
"\n";
314 include DOL_DOCUMENT_ROOT.
'/core/tpl/commonfields_add.tpl.php';
317 include DOL_DOCUMENT_ROOT.
'/core/tpl/extrafields_add.tpl.php';
319 print
'</table>'.
"\n";
323 print
$form->buttonsSaveCancel(
"Create");
329 if (($id || $ref) && $action ==
'edit') {
332 print
'<form method="POST" action="'.$_SERVER[
"PHP_SELF"].
'">';
333 print
'<input type="hidden" name="token" value="'.newToken().
'">';
334 print
'<input type="hidden" name="action" value="update">';
335 print
'<input type="hidden" name="backtopage" value="'.$backtopage.
'">';
336 print
'<input type="hidden" name="id" value="'.$object->id.
'">';
342 print
'<table class="border centpercent tableforfieldedit">'.
"\n";
345 include DOL_DOCUMENT_ROOT.
'/core/tpl/commonfields_edit.tpl.php';
348 include DOL_DOCUMENT_ROOT.
'/core/tpl/extrafields_edit.tpl.php';
354 print
$form->buttonsSaveCancel(
"Create");
360 if ($object->id > 0 && (empty($action) || ($action !=
'edit' && $action !=
'create'))) {
367 if ($action ==
'delete') {
368 $formconfirm =
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.$object->id, $langs->trans(
'DeleteBillOfMaterials'), $langs->trans(
'ConfirmDeleteBillOfMaterials'),
'confirm_delete',
'', 0, 1);
371 if ($action ==
'deleteline') {
372 $formconfirm =
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.$object->id.
'&lineid='.$lineid, $langs->trans(
'DeleteLine'), $langs->trans(
'ConfirmDeleteLine'),
'confirm_deleteline',
'', 0, 1);
376 if ($action ==
'validate') {
378 $ref = substr($object->ref, 1, 4);
379 if ($ref ==
'PROV') {
380 $object->fetch_product();
381 $numref = $object->getNextNumRef($object->product);
383 $numref = $object->ref;
386 $text = $langs->trans(
'ConfirmValidateBom', $numref);
395 $formquestion = array();
399 if ($conf->browser->name ==
'ie') {
402 $formquestion = array(
409 $formconfirm =
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.$object->id, $langs->trans(
'Validate'), $text,
'confirm_validate', $formquestion, 0, 1, 220);
413 if ($action ==
'close') {
414 $text = $langs->trans(
'ConfirmCloseBom', $object->ref);
423 $formquestion = array();
427 if ($conf->browser->name ==
'ie') {
430 $formquestion = array(
437 $formconfirm =
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.$object->id, $langs->trans(
'Close'), $text,
'confirm_close', $formquestion, 0, 1, 220);
441 if ($action ==
'reopen') {
442 $text = $langs->trans(
'ConfirmReopenBom', $object->ref);
451 $formquestion = array();
454 require_once DOL_DOCUMENT_ROOT.
'/product/class/html.formproduct.class.php';
456 if ($conf->browser->name ==
'ie') {
459 $formquestion = array(
466 $formconfirm =
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.$object->id, $langs->trans(
'ReOpen'), $text,
'confirm_reopen', $formquestion, 0, 1, 220);
470 if ($action ==
'clone') {
472 $formquestion = array();
473 $formconfirm =
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.$object->id, $langs->trans(
'ToClone'), $langs->trans(
'ConfirmCloneBillOfMaterials', $object->ref),
'confirm_clone', $formquestion,
'yes', 1);
477 if ($action ==
'setdraft') {
478 $text = $langs->trans(
'ConfirmSetToDraft', $object->ref);
480 $formquestion = array();
481 $formconfirm =
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.$object->id, $langs->trans(
'SetToDraft'), $text,
'confirm_setdraft', $formquestion, 0, 1, 220);
485 $parameters = array(
'formConfirm' =>
$formconfirm,
'lineid' => $lineid);
486 $reshook = $hookmanager->executeHooks(
'formConfirm', $parameters, $object, $action);
487 if (empty($reshook)) {
489 } elseif ($reshook > 0) {
499 $linkback =
'<a href="'.DOL_URL_ROOT.
'/bom/bom_list.php?restore_lastsearch_values=1'.(!empty($socid) ?
'&socid='.$socid :
'').
'">'.$langs->trans(
"BackToList").
'</a>';
501 $morehtmlref =
'<div class="refidno">';
539 $morehtmlref .=
'</div>';
542 dol_banner_tab($object,
'ref', $linkback, 1,
'ref',
'ref', $morehtmlref);
545 print
'<div class="fichecenter">';
546 print
'<div class="fichehalfleft">';
547 print
'<div class="underbanner clearboth"></div>';
548 print
'<table class="border centpercent tableforfield">'.
"\n";
551 $keyforbreak =
'duration';
552 include DOL_DOCUMENT_ROOT.
'/core/tpl/commonfields_view.tpl.php';
553 $object->calculateCosts();
554 print
'<tr><td>'.$form->textwithpicto($langs->trans(
"TotalCost"), $langs->trans(
"BOMTotalCost")).
'</td><td><span class="amount">'.
price($object->total_cost).
'</span></td></tr>';
555 print
'<tr><td>'.$langs->trans(
"UnitCost").
'</td><td>'.
price($object->unit_cost).
'</td></tr>';
558 include DOL_DOCUMENT_ROOT.
'/core/tpl/extrafields_view.tpl.php';
564 print
'<div class="clearboth"></div>';
574 if (!empty($object->table_element_line)) {
576 $res = $object->fetchLinesbytypeproduct(0);
577 $object->calculateCosts();
579 print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ?
'' :
load_fiche_titre($langs->trans(
'BOMProductsList'),
'',
'product');
581 print
' <form name="addproduct" id="addproduct" action="' . $_SERVER[
"PHP_SELF"] .
'?id=' . $object->id . (($action !=
'editline') ?
'' :
'') .
'" method="POST">
582 <input type="hidden" name="token" value="' .
newToken() .
'">
583 <input type="hidden" name="action" value="' . (($action !=
'editline') ?
'addline' :
'updateline') .
'">
584 <input type="hidden" name="mode" value="">
585 <input type="hidden" name="page_y" value="">
586 <input type="hidden" name="id" value="' . $object->id .
'">
589 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
590 include DOL_DOCUMENT_ROOT.
'/core/tpl/ajaxrow.tpl.php';
593 print
'<div class="div-table-responsive-no-min">';
594 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action !=
'selectlines' && $action !=
'editline')) {
595 print
'<table id="tablelines" class="noborder noshadow centpercent">';
598 if (!empty($object->lines)) {
599 $object->printObjectLines($action, $mysoc,
null,
GETPOST(
'lineid',
'int'), 1,
'/bom/tpl');
603 if ($object->status == 0 && $permissiontoadd && $action !=
'selectlines') {
604 if ($action !=
'editline') {
608 $parameters = array();
609 $reshook = $hookmanager->executeHooks(
'formAddObjectLine', $parameters, $object, $action);
610 if ($reshook < 0)
setEventMessages($hookmanager->error, $hookmanager->errors,
'errors');
612 $object->formAddObjectLine(1, $mysoc,
null,
'/bom/tpl');
616 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action !=
'selectlines' && $action !=
'editline')) {
625 $res = $object->fetchLinesbytypeproduct(1);
626 $object->calculateCosts();
628 print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ?
'' :
load_fiche_titre($langs->trans(
'BOMServicesList'),
'',
'service');
630 print
' <form name="addservice" id="addservice" action="' . $_SERVER[
"PHP_SELF"] .
'?id=' . $object->id . (($action !=
'editline') ?
'' :
'') .
'" method="POST">
631 <input type="hidden" name="token" value="' .
newToken() .
'">
632 <input type="hidden" name="action" value="' . (($action !=
'editline') ?
'addline' :
'updateline') .
'">
633 <input type="hidden" name="mode" value="">
634 <input type="hidden" name="page_y" value=""> <input type="hidden" name="id" value="' . $object->id .
'">
637 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
638 $tagidfortablednd =
'tablelinesservice';
639 include DOL_DOCUMENT_ROOT .
'/core/tpl/ajaxrow.tpl.php';
642 print
'<div class="div-table-responsive-no-min">';
643 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action !=
'selectlines' && $action !=
'editline')) {
644 print
'<table id="tablelinesservice" class="noborder noshadow centpercent">';
647 if (!empty($object->lines)) {
648 $object->printObjectLines($action, $mysoc,
null,
GETPOST(
'lineid',
'int'), 1,
'/bom/tpl');
652 if ($object->status == 0 && $permissiontoadd && $action !=
'selectlines') {
653 if ($action !=
'editline') {
655 $parameters = array();
656 $reshook = $hookmanager->executeHooks(
'formAddObjectServiceLine', $parameters, $object, $action);
657 if ($reshook < 0)
setEventMessages($hookmanager->error, $hookmanager->errors,
'errors');
659 $object->formAddObjectLine(1, $mysoc,
null,
'/bom/tpl');
664 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action !=
'selectlines' && $action !=
'editline')) {
675 $res = $object->fetchLines();
679 if ($action !=
'presend' && $action !=
'editline') {
680 print
'<div class="tabsAction">'.
"\n";
681 $parameters = array();
682 $reshook = $hookmanager->executeHooks(
'addMoreActionsButtons', $parameters, $object, $action);
687 if (empty($reshook)) {
694 if ($object->status == $object::STATUS_VALIDATED) {
695 if ($permissiontoadd) {
696 print
'<a class="butAction" href="'.$_SERVER[
'PHP_SELF'].
'?id='.$object->id.
'&action=setdraft&token='.
newToken().
'">'.$langs->trans(
"SetToDraft").
'</a>'.
"\n";
701 if ($object->status == $object::STATUS_DRAFT) {
702 if ($permissiontoadd) {
703 print
'<a class="butAction" href="'.$_SERVER[
"PHP_SELF"].
'?id='.$object->id.
'&action=edit&token='.
newToken().
'">'.$langs->trans(
"Modify").
'</a>'.
"\n";
705 print
'<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans(
"NotEnoughPermissions")).
'">'.$langs->trans(
'Modify').
'</a>'.
"\n";
710 if ($object->status == $object::STATUS_DRAFT) {
711 if ($permissiontoadd) {
712 if (is_array($object->lines) && count($object->lines) > 0) {
713 print
'<a class="butAction" href="'.$_SERVER[
'PHP_SELF'].
'?id='.$object->id.
'&action=validate&token='.
newToken().
'">'.$langs->trans(
"Validate").
'</a>'.
"\n";
715 $langs->load(
"errors");
716 print
'<a class="butActionRefused" href="" title="'.$langs->trans(
"ErrorAddAtLeastOneLineFirst").
'">'.$langs->trans(
"Validate").
'</a>'.
"\n";
722 if ($permissiontoadd && $object->status == $object::STATUS_CANCELED) {
723 print
'<a class="butAction" href="'.$_SERVER[
'PHP_SELF'].
'?id='.$object->id.
'&action=reopen&token='.
newToken().
'">'.$langs->trans(
"ReOpen").
'</a>'.
"\n";
728 if ($object->status == $object::STATUS_VALIDATED && !empty($user->rights->mrp->write)) {
729 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";
734 if ($permissiontoadd) {
735 print
dolGetButtonAction($langs->trans(
"ToClone"),
'',
'default', $_SERVER[
'PHP_SELF'].
'?id='.$object->id.(!empty($object->socid) ?
'&socid='.$object->socid :
"").
'&action=clone&object=bom',
'clone', $permissiontoadd);
739 if ($permissiontoadd && $object->status == $object::STATUS_VALIDATED) {
740 print
'<a class="butActionDelete" href="'.$_SERVER[
'PHP_SELF'].
'?id='.$object->id.
'&action=close&token='.
newToken().
'">'.$langs->trans(
"Disable").
'</a>'.
"\n";
758 print
dolGetButtonAction($langs->trans(
"Delete"),
'',
'delete', $_SERVER[
"PHP_SELF"].
'?id='.$object->id.
'&action=delete&token='.
newToken(),
'delete', $permissiontodelete);
765 if (
GETPOST(
'modelselected')) {
769 if ($action !=
'presend') {
770 print
'<div class="fichecenter"><div class="fichehalfleft">';
771 print
'<a name="builddoc"></a>';
775 $relativepath = $objref.
'/'.$objref.
'.pdf';
776 $filedir = $conf->bom->dir_output.
'/'.$objref;
777 $urlsource = $_SERVER[
"PHP_SELF"].
"?id=".$object->id;
778 $genallowed = $user->hasRight(
'bom',
'read');
779 $delallowed = $user->hasRight(
'bom',
'write');
780 print $formfile->showdocuments(
'bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0,
'',
'',
'', $langs->defaultlang);
783 $linktoelem =
$form->showLinkToObjectBlock($object,
null, array(
'bom'));
784 $somethingshown =
$form->showLinkedObjectBlock($object, $linktoelem);
787 print
'</div><div class="fichehalfright">';
791 $morehtmlcenter =
dolGetButtonTitle($langs->trans(
'SeeAll'),
'',
'fa fa-bars imgforviewmode', DOL_URL_ROOT.
'/bom/bom_agenda.php?id='.$object->id);
794 include_once DOL_DOCUMENT_ROOT.
'/core/class/html.formactions.class.php';
796 $somethingshown =
$formactions->showactions($object, $object->element, 0, 1,
'', $MAXEVENT,
'', $morehtmlcenter);
798 print
'</div></div>';
802 if (
GETPOST(
'modelselected')) {
808 $defaulttopic =
'InformationMessage';
809 $diroutput = $conf->bom->dir_output;
810 $trackid =
'bom'.$object->id;
812 include DOL_DOCUMENT_ROOT.
'/core/tpl/card_presend.tpl.php';