Merge pull request #21498 from atm-lena/develop_NEW_Service_DefaultWorkstation

Develop new service management in BOM
This commit is contained in:
Laurent Destailleur 2022-09-13 01:44:58 +02:00 committed by GitHub
commit fe68e364f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 928 additions and 355 deletions

67
htdocs/bom/ajax/ajax.php Normal file
View File

@ -0,0 +1,67 @@
<?php
/**
* Copyright (C) 2020 Laurent Destailleur <eldy@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/bom/ajax/ajax.php
* \brief Ajax component for BOM.
*/
if (!defined('NOTOKENRENEWAL')) {
define('NOTOKENRENEWAL', '1'); // Disables token renewal
}
if (!defined('NOREQUIREHTML')) {
define('NOREQUIREHTML', '1');
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
if (!defined('NOREQUIRESOC')) {
define('NOREQUIRESOC', '1');
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
if (!defined('NOBROWSERNOTIF')) {
define('NOBROWSERNOTIF', '1');
}
include_once '../../main.inc.php'; // Load $user and permissions
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
$action = GETPOST('action', 'aZ09');
$idproduct = GETPOST('idproduct', 'int');
/*
* View
*/
top_httphead();
if ($action == 'getDurationUnitByProduct' && $user->hasRight('product', 'lire')) {
$product = new Product($db);
$res = $product->fetch($idproduct);
$cUnit = new CUnits($db);
$fk_unit = $cUnit->getUnitFromCode($product->duration_unit, 'short_label', 'time');
echo json_encode($fk_unit);
exit();
}

View File

@ -34,6 +34,8 @@ require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp.lib.php';
// Load translation files required by the page
$langs->loadLangs(array('mrp', 'other'));
global $filtertype;
// Get parameters
$id = GETPOST('id', 'int');
$ref = GETPOST('ref', 'alpha');
@ -158,14 +160,14 @@ if (empty($reshook)) {
$idprod = $bom_child->fk_product;
}
} else {
$idprod = (int) GETPOST('idprod', 'int');
$idprod = (!empty(GETPOST('idprodservice', 'int')) ? GETPOST('idprodservice', 'int') : (int) GETPOST('idprod', 'int'));
}
$qty = price2num(GETPOST('qty', 'alpha'), 'MS');
$qty_frozen = price2num(GETPOST('qty_frozen', 'alpha'), 'MS');
$disable_stock_change = GETPOST('disable_stock_change', 'int');
$efficiency = price2num(GETPOST('efficiency', 'alpha'));
$fk_unit = GETPOST('fk_unit', 'alphanohtml');
if ($qty == '') {
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
$error++;
@ -191,19 +193,22 @@ if (empty($reshook)) {
}
if (!$error) {
$result = $object->addLine($idprod, $qty, $qty_frozen, $disable_stock_change, $efficiency, -1, $bom_child_id, null);
$result = $object->addLine($idprod, $qty, $qty_frozen, $disable_stock_change, $efficiency, -1, $bom_child_id, null, $fk_unit);
if ($result <= 0) {
setEventMessages($object->error, $object->errors, 'errors');
$action = '';
} else {
unset($_POST['idprod']);
unset($_POST['idprodservice']);
unset($_POST['qty']);
unset($_POST['qty_frozen']);
unset($_POST['disable_stock_change']);
$object->fetchLines();
}
$object->fetchLines();
$object->calculateCosts();
}
}
@ -217,6 +222,7 @@ if (empty($reshook)) {
$qty_frozen = price2num(GETPOST('qty_frozen', 'alpha'), 'MS');
$disable_stock_change = GETPOST('disable_stock_change', 'int');
$efficiency = price2num(GETPOST('efficiency', 'alpha'));
$fk_unit = GETPOST('fk_unit', 'alphanohtml');
if ($qty == '') {
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
@ -227,248 +233,250 @@ if (empty($reshook)) {
$bomline = new BOMLine($db);
$bomline->fetch($lineid);
$result = $object->updateLine($lineid, $qty, (int) $qty_frozen, (int) $disable_stock_change, $efficiency, $bomline->position, $bomline->import_key);
$result = $object->updateLine($lineid, $qty, (int) $qty_frozen, (int) $disable_stock_change, $efficiency, $bomline->position, $bomline->import_key, $fk_unit);
if ($result <= 0) {
setEventMessages($object->error, $object->errors, 'errors');
$action = '';
} else {
unset($_POST['idprod']);
unset($_POST['idprodservice']);
unset($_POST['qty']);
unset($_POST['qty_frozen']);
unset($_POST['disable_stock_change']);
$object->fetchLines();
}
$object->fetchLines();
$object->calculateCosts();
}
}
}
/*
* View
*/
/*
* View
*/
$form = new Form($db);
$formfile = new FormFile($db);
$form = new Form($db);
$formfile = new FormFile($db);
$title = $langs->trans('BOM');
$help_url ='EN:Module_BOM';
llxHeader('', $title, $help_url);
$title = $langs->trans('BOM');
$help_url ='EN:Module_BOM';
llxHeader('', $title, $help_url);
// Part to create
if ($action == 'create') {
print load_fiche_titre($langs->trans("NewBOM"), '', 'bom');
// Part to create
if ($action == 'create') {
print load_fiche_titre($langs->trans("NewBOM"), '', 'bom');
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="add">';
print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="add">';
print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
print dol_get_fiche_head(array(), '');
print dol_get_fiche_head(array(), '');
print '<table class="border centpercent tableforfieldcreate">'."\n";
print '<table class="border centpercent tableforfieldcreate">'."\n";
// Common attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_add.tpl.php';
// Common attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_add.tpl.php';
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
print '</table>'."\n";
print '</table>'."\n";
print dol_get_fiche_end();
print dol_get_fiche_end();
print $form->buttonsSaveCancel("Create");
print $form->buttonsSaveCancel("Create");
print '</form>';
}
// Part to edit record
if (($id || $ref) && $action == 'edit') {
print load_fiche_titre($langs->trans("BillOfMaterials"), '', 'cubes');
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="update">';
print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
print '<input type="hidden" name="id" value="'.$object->id.'">';
print dol_get_fiche_head();
//$object->fields['keyfield']['disabled'] = 1;
print '<table class="border centpercent tableforfieldedit">'."\n";
// Common attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_edit.tpl.php';
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_edit.tpl.php';
print '</table>';
print dol_get_fiche_end();
print $form->buttonsSaveCancel("Create");
print '</form>';
}
// Part to show record
if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
$head = bomPrepareHead($object);
print dol_get_fiche_head($head, 'card', $langs->trans("BillOfMaterials"), -1, 'bom');
$formconfirm = '';
// Confirmation to delete
if ($action == 'delete') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteBillOfMaterials'), $langs->trans('ConfirmDeleteBillOfMaterials'), 'confirm_delete', '', 0, 1);
}
// Confirmation to delete line
if ($action == 'deleteline') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
print '</form>';
}
// Confirmation of validation
if ($action == 'validate') {
// We check that object has a temporary ref
$ref = substr($object->ref, 1, 4);
if ($ref == 'PROV') {
$object->fetch_product();
$numref = $object->getNextNumRef($object->product);
} else {
$numref = $object->ref;
// Part to edit record
if (($id || $ref) && $action == 'edit') {
print load_fiche_titre($langs->trans("BillOfMaterials"), '', 'cubes');
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="update">';
print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
print '<input type="hidden" name="id" value="'.$object->id.'">';
print dol_get_fiche_head();
//$object->fields['keyfield']['disabled'] = 1;
print '<table class="border centpercent tableforfieldedit">'."\n";
// Common attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_edit.tpl.php';
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_edit.tpl.php';
print '</table>';
print dol_get_fiche_end();
print $form->buttonsSaveCancel("Create");
print '</form>';
}
// Part to show record
if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
$head = bomPrepareHead($object);
print dol_get_fiche_head($head, 'card', $langs->trans("BillOfMaterials"), -1, 'bom');
$formconfirm = '';
// Confirmation to delete
if ($action == 'delete') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteBillOfMaterials'), $langs->trans('ConfirmDeleteBillOfMaterials'), 'confirm_delete', '', 0, 1);
}
// Confirmation to delete line
if ($action == 'deleteline') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
}
$text = $langs->trans('ConfirmValidateBom', $numref);
/*if (!empty($conf->notification->enabled))
{
// Confirmation of validation
if ($action == 'validate') {
// We check that object has a temporary ref
$ref = substr($object->ref, 1, 4);
if ($ref == 'PROV') {
$object->fetch_product();
$numref = $object->getNextNumRef($object->product);
} else {
$numref = $object->ref;
}
$text = $langs->trans('ConfirmValidateBom', $numref);
/*if (! empty($conf->notification->enabled))
{
require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
$notify = new Notify($db);
$text .= '<br>';
$text .= $notify->confirmMessage('BOM_VALIDATE', $object->socid, $object);
}*/
}*/
$formquestion = array();
if (!empty($conf->bom->enabled)) {
$langs->load("mrp");
$forcecombo = 0;
if ($conf->browser->name == 'ie') {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
$formquestion = array();
if (!empty($conf->bom->enabled)) {
$langs->load("mrp");
$forcecombo = 0;
if ($conf->browser->name == 'ie') {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
);
);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
}
// Confirmation of closing
if ($action == 'close') {
$text = $langs->trans('ConfirmCloseBom', $object->ref);
/*if (! empty($conf->notification->enabled))
{
// Confirmation of closing
if ($action == 'close') {
$text = $langs->trans('ConfirmCloseBom', $object->ref);
/*if (! empty($conf->notification->enabled))
{
require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
$notify = new Notify($db);
$text .= '<br>';
$text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
}*/
}*/
$formquestion = array();
if (!empty($conf->bom->enabled)) {
$langs->load("mrp");
$forcecombo = 0;
if ($conf->browser->name == 'ie') {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
$formquestion = array();
if (!empty($conf->bom->enabled)) {
$langs->load("mrp");
$forcecombo = 0;
if ($conf->browser->name == 'ie') {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
);
);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
}
// Confirmation of reopen
if ($action == 'reopen') {
$text = $langs->trans('ConfirmReopenBom', $object->ref);
/*if (! empty($conf->notification->enabled))
{
require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
$notify = new Notify($db);
$text .= '<br>';
$text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
}*/
// Confirmation of reopen
if ($action == 'reopen') {
$text = $langs->trans('ConfirmReopenBom', $object->ref);
/*if (! empty($conf->notification->enabled))
{
require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
$notify = new Notify($db);
$text .= '<br>';
$text .= $notify->confirmMessage('BOM_CLOSE', $object->socid, $object);
}*/
$formquestion = array();
if (!empty($conf->bom->enabled)) {
$langs->load("mrp");
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
$forcecombo = 0;
if ($conf->browser->name == 'ie') {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
$formquestion = array();
if (!empty($conf->bom->enabled)) {
$langs->load("mrp");
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
$forcecombo = 0;
if ($conf->browser->name == 'ie') {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
);
);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $text, 'confirm_reopen', $formquestion, 0, 1, 220);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $text, 'confirm_reopen', $formquestion, 0, 1, 220);
}
// Clone confirmation
if ($action == 'clone') {
// Create an array for form
$formquestion = array();
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneBillOfMaterials', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
}
// Clone confirmation
if ($action == 'clone') {
// Create an array for form
$formquestion = array();
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneBillOfMaterials', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
}
// Confirmation of action xxxx
if ($action == 'setdraft') {
$text = $langs->trans('ConfirmSetToDraft', $object->ref);
// Confirmation of action xxxx
if ($action == 'setdraft') {
$text = $langs->trans('ConfirmSetToDraft', $object->ref);
$formquestion = array();
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220);
}
$formquestion = array();
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220);
}
// Call Hook formConfirm
$parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$formconfirm .= $hookmanager->resPrint;
} elseif ($reshook > 0) {
$formconfirm = $hookmanager->resPrint;
}
// Call Hook formConfirm
$parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$formconfirm .= $hookmanager->resPrint;
} elseif ($reshook > 0) {
$formconfirm = $hookmanager->resPrint;
}
// Print form confirm
print $formconfirm;
// Print form confirm
print $formconfirm;
// Object card
// ------------------------------------------------------------
$linkback = '<a href="'.DOL_URL_ROOT.'/bom/bom_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
// Object card
// ------------------------------------------------------------
$linkback = '<a href="'.DOL_URL_ROOT.'/bom/bom_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
$morehtmlref = '<div class="refidno">';
/*
// Ref bis
$morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', 0, 1);
$morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', null, null, '', 1);
// Thirdparty
$morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1);
// Project
if (isModEnabled('project'))
{
$morehtmlref = '<div class="refidno">';
/*
// Ref bis
$morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', 0, 1);
$morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->bom->creer, 'string', '', null, null, '', 1);
// Thirdparty
$morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1);
// Project
if (isModEnabled('project'))
{
$langs->load("projects");
$morehtmlref.='<br>'.$langs->trans('Project') . ' ';
if ($permissiontoadd)
@ -495,76 +503,133 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
$morehtmlref.='';
}
}
}
*/
$morehtmlref .= '</div>';
}
*/
$morehtmlref .= '</div>';
dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
print '<div class="fichecenter">';
print '<div class="fichehalfleft">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border centpercent tableforfield">'."\n";
print '<div class="fichecenter">';
print '<div class="fichehalfleft">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border centpercent tableforfield">'."\n";
// Common attributes
$keyforbreak = 'duration';
include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
$object->calculateCosts();
print '<tr><td>'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).'</td><td><span class="amount">'.price($object->total_cost).'</span></td></tr>';
print '<tr><td>'.$langs->trans("UnitCost").'</td><td>'.price($object->unit_cost).'</td></tr>';
// Common attributes
$keyforbreak = 'duration';
include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
$object->calculateCosts();
print '<tr><td>'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).'</td><td><span class="amount">'.price($object->total_cost).'</span></td></tr>';
print '<tr><td>'.$langs->trans("UnitCost").'</td><td>'.price($object->unit_cost).'</td></tr>';
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
print '</table>';
print '</div>';
print '</div>';
print '</table>';
print '</div>';
print '</div>';
print '<div class="clearboth"></div>';
print '<div class="clearboth"></div>';
print dol_get_fiche_end();
print dol_get_fiche_end();
/*
* Lines
*/
/*
* Lines
*/
if (!empty($object->table_element_line)) {
print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.(($action != 'editline') ? '' : '').'" method="POST">
<input type="hidden" name="token" value="' . newToken().'">
<input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
if (!empty($object->table_element_line)) {
//Products
$res = $object->fetchLinesbytypeproduct(0);
$object->calculateCosts();
print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product');
print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '' : '') . '" method="POST">
<input type="hidden" name="token" value="' . newToken() . '">
<input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
<input type="hidden" name="mode" value="">
<input type="hidden" name="page_y" value="">
<input type="hidden" name="id" value="' . $object->id.'">
<input type="hidden" name="id" value="' . $object->id . '">
';
if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
}
if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
}
print '<div class="div-table-responsive-no-min">';
if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
print '<table id="tablelines" class="noborder noshadow" width="100%">';
}
print '<div class="div-table-responsive-no-min">';
if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
print '<table id="tablelines" class="noborder noshadow" width="100%">';
}
if (!empty($object->lines)) {
$object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/bom/tpl');
}
if (!empty($object->lines)) {
$object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/bom/tpl');
}
// Form to add new line
if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
if ($action != 'editline') {
// Add products/services form
// Form to add new line
if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
if ($action != 'editline') {
// Add products/services form
$parameters = array();
$reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
if (empty($reshook))
$parameters = array();
$reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
if (empty($reshook))
$object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
}
}
if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
print '</table>';
}
print '</div>';
print "</form>\n";
mrpCollapseBomManagement();
//Services
$filtertype = 1;
$res = $object->fetchLinesbytypeproduct(1);
$object->calculateCosts();
print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service');
print ' <form name="addservice" id="addservice" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '' : '') . '" method="POST">
<input type="hidden" name="token" value="' . newToken() . '">
<input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
<input type="hidden" name="mode" value="">
<input type="hidden" name="page_y" value=""> <input type="hidden" name="id" value="' . $object->id . '">
';
if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
$tagidfortablednd = 'tablelinesservice';
include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
}
print '<div class="div-table-responsive-no-min">';
if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
print '<table id="tablelinesservice" class="noborder noshadow" width="100%">';
}
if (!empty($object->lines)) {
$object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/bom/tpl');
}
// Form to add new line
if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
if ($action != 'editline') {
// Add services form
$parameters = array();
$reshook = $hookmanager->executeHooks('formAddObjectServiceLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
if (empty($reshook))
$object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
}
}
}
@ -578,6 +643,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
mrpCollapseBomManagement();
}
$res = $object->fetchLines();
// Buttons for actions

View File

@ -23,6 +23,8 @@
// Put here all includes required by your class file
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
@ -399,6 +401,58 @@ class BOM extends CommonObject
return $result;
}
/**
* Load object lines in memory from the database by type of product
*
* @param int $typeproduct 0 type product, 1 type service
* @return int <0 if KO, 0 if not found, >0 if OK
*/
public function fetchLinesbytypeproduct($typeproduct = 0)
{
$this->lines = array();
$objectlineclassname = get_class($this).'Line';
if (!class_exists($objectlineclassname)) {
$this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon';
return -1;
}
$objectline = new $objectlineclassname($this->db);
$sql = "SELECT ".$objectline->getFieldList('l');
$sql .= " FROM ".$this->db->prefix().$objectline->table_element." as l";
$sql .= " LEFT JOIN ".$this->db->prefix()."product as p ON p.rowid = l.fk_product";
$sql .= " WHERE l.fk_".$this->db->escape($this->element)." = ".((int) $this->id);
$sql .= " AND p.fk_product_type = ". ((int) $typeproduct);
if (isset($objectline->fields['position'])) {
$sql .= $this->db->order('position', 'ASC');
}
$resql = $this->db->query($sql);
if ($resql) {
$num_rows = $this->db->num_rows($resql);
$i = 0;
while ($i < $num_rows) {
$obj = $this->db->fetch_object($resql);
if ($obj) {
$newline = new $objectlineclassname($this->db);
$newline->setVarsFromFetchObj($obj);
$this->lines[] = $newline;
}
$i++;
}
return $num_rows;
} else {
$this->error = $this->db->lasterror();
$this->errors[] = $this->error;
return -1;
}
}
/**
* Load list of objects in memory from the database.
*
@ -515,7 +569,7 @@ class BOM extends CommonObject
* @param string $import_key Import Key
* @return int <0 if KO, Id of created object if OK
*/
public function addLine($fk_product, $qty, $qty_frozen = 0, $disable_stock_change = 0, $efficiency = 1.0, $position = -1, $fk_bom_child = null, $import_key = null)
public function addLine($fk_product, $qty, $qty_frozen = 0, $disable_stock_change = 0, $efficiency = 1.0, $position = -1, $fk_bom_child = null, $import_key = null, $fk_unit = '')
{
global $mysoc, $conf, $langs, $user;
@ -583,6 +637,7 @@ class BOM extends CommonObject
$this->line->fk_bom_child = $fk_bom_child;
$this->line->import_key = $import_key;
$this->line->position = $rankToUse;
$this->line->fk_unit = $fk_unit;
$result = $this->line->create($user);
@ -612,9 +667,10 @@ class BOM extends CommonObject
* @param float $efficiency Efficiency in MO
* @param int $position Position of BOM-Line in BOM-Lines
* @param string $import_key Import Key
* @param int $fk_unit Unit of line
* @return int <0 if KO, Id of updated BOM-Line if OK
*/
public function updateLine($rowid, $qty, $qty_frozen = 0, $disable_stock_change = 0, $efficiency = 1.0, $position = -1, $import_key = null)
public function updateLine($rowid, $qty, $qty_frozen = 0, $disable_stock_change = 0, $efficiency = 1.0, $position = -1, $import_key = null, $fk_unit = 0)
{
global $mysoc, $conf, $langs, $user;
@ -684,6 +740,7 @@ class BOM extends CommonObject
$this->line->efficiency = $efficiency;
$this->line->import_key = $import_key;
$this->line->position = $rankToUse;
if(!empty($fk_unit)) $this->line->fk_unit = $fk_unit;
$result = $this->line->update($user);
@ -1260,6 +1317,8 @@ class BOM extends CommonObject
*/
public function calculateCosts()
{
global $conf;
include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
$this->unit_cost = 0;
$this->total_cost = 0;
@ -1272,38 +1331,62 @@ class BOM extends CommonObject
foreach ($this->lines as &$line) {
$tmpproduct->cost_price = 0;
$tmpproduct->pmp = 0;
$result = $tmpproduct->fetch($line->fk_product, '', '', '', 0, 1, 1); // We discard selling price and language loading
if (empty($line->fk_bom_child)) {
$result = $tmpproduct->fetch($line->fk_product, '', '', '', 0, 1, 1); // We discard selling price and language loading
if ($result < 0) {
$this->error = $tmpproduct->error;
return -1;
}
$line->unit_cost = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
if (empty($line->unit_cost)) {
if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0) {
$line->unit_cost = $productFournisseur->fourn_unitprice;
if ($tmpproduct->type == $tmpproduct::TYPE_PRODUCT) {
if (empty($line->fk_bom_child)) {
if ($result < 0) {
$this->error = $tmpproduct->error;
return -1;
}
$line->unit_cost = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
if (empty($line->unit_cost)) {
if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0) {
$line->unit_cost = $productFournisseur->fourn_unitprice;
}
}
$line->total_cost = price2num($line->qty * $line->unit_cost, 'MT');
$this->total_cost += $line->total_cost;
} else {
$bom_child = new BOM($this->db);
$res = $bom_child->fetch($line->fk_bom_child);
if ($res > 0) {
$bom_child->calculateCosts();
$line->childBom[] = $bom_child;
$this->total_cost += $bom_child->total_cost * $line->qty;
} else {
$this->error = $bom_child->error;
return -2;
}
}
} else {
//Convert qty to hour
$unit = measuringUnitString($line->fk_unit, '', '', 1);
$qty = convertDurationtoHour($line->qty, $unit);
$line->total_cost = price2num($line->qty * $line->unit_cost, 'MT');
if ($conf->workstation->enabled) {
if ($tmpproduct->fk_default_workstation) {
$workstation = new Workstation($this->db);
$res = $workstation->fetch($tmpproduct->fk_default_workstation);
if ($res > 0) $line->total_cost = price2num($qty * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated), 'MT');
else {
$this->error = $workstation->error;
return -3;
}
}
} else {
$line->total_cost = price2num($qty * $tmpproduct->cost_price, 'MT');
}
$this->total_cost += $line->total_cost;
} else {
$bom_child= new BOM($this->db);
$res = $bom_child->fetch($line->fk_bom_child);
if ($res>0) {
$bom_child->calculateCosts();
$line->childBom[] = $bom_child;
$this->total_cost += $bom_child->total_cost * $line->qty;
} else {
$this->error = $bom_child->error;
return -2;
}
}
}
$this->total_cost = price2num($this->total_cost, 'MT');
if ($this->qty > 0) {
$this->unit_cost = price2num($this->total_cost / $this->qty, 'MU');
} elseif ($this->qty < 0) {
@ -1478,6 +1561,7 @@ class BOMLine extends CommonObjectLine
'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
'disable_stock_change' => array('type'=>'smallint', 'label'=>'DisableStockChange', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>108, 'css'=>'maxwidth50imp', 'help'=>'DisableStockChangeHelp'),
'efficiency' => array('type'=>'double(24,8)', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'position'=>110, 'notnull'=>1, 'css'=>'maxwidth50imp', 'help'=>'ValueOfEfficiencyConsumedMeans'),
'fk_unit' => array('type'=>'integer', 'label'=>'Unit', 'enabled'=>1, 'visible'=>1, 'position'=>120, 'notnull'=>-1,),
'position' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>1, 'visible'=>0, 'default'=>0, 'position'=>200, 'notnull'=>1,),
'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
);

View File

@ -29,6 +29,8 @@
* $forceall (0 by default, 1 for supplier invoices/orders)
*/
require_once DOL_DOCUMENT_ROOT."/product/class/html.formproduct.class.php";
// Protection to avoid direct call of template
if (empty($object) || !is_object($object)) {
print "Error: this template page cannot be called directly as an URL";
@ -36,12 +38,18 @@ if (empty($object) || !is_object($object)) {
}
global $forceall, $forcetoshowtitlelines;
global $forceall, $forcetoshowtitlelines, $filtertype;
if (empty($forceall)) {
$forceall = 0;
}
if (empty($filtertype)) $filtertype = 0;
if (!empty($object->element) && $object->element == 'contrat' && empty($conf->global->STOCK_SUPPORT_SERVICES)) {
$filtertype = -1;
}
$formproduct = new FormProduct($object->db);
// Define colspan for the button 'Add'
$colspan = 3; // Columns: total ht + col edit + col delete
@ -53,6 +61,7 @@ $objectline = new BOMLine($this->db);
print "<!-- BEGIN PHP TEMPLATE objectline_create.tpl.php -->\n";
$nolinesbefore = (count($this->lines) == 0 || $forcetoshowtitlelines);
if ($nolinesbefore) {
print '<tr class="liste_titre nodrag nodrop">';
if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
@ -62,16 +71,24 @@ if ($nolinesbefore) {
print '<div id="add"></div><span class="hideonsmartphone">'.$langs->trans('AddNewLine').'</span>';
print '</td>';
print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="linecoluseunit left">';
print '<span id="title_units">';
print $langs->trans('Unit');
print '</span></td>';
if ($filtertype != 1) {
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="linecoluseunit left">';
print '<span id="title_units">';
print $langs->trans('Unit');
print '</span></td>';
}
print '<td class="linecolqtyfrozen right">' . $form->textwithpicto($langs->trans('QtyFrozen'), $langs->trans("QuantityConsumedInvariable")) . '</td>';
print '<td class="linecoldisablestockchange right">' . $form->textwithpicto($langs->trans('DisableStockChange'), $langs->trans('DisableStockChangeHelp')) . '</td>';
print '<td class="linecollost right">' . $form->textwithpicto($langs->trans('ManufacturingEfficiency'), $langs->trans('ValueOfMeansLoss')) . '</td>';
} else {
print '<td class="linecolunit right">' . $form->textwithpicto($langs->trans('Unit'), '').'</td>';
if ($conf->workstation->enabled) print '<td class="linecolworkstation right">' . $form->textwithpicto($langs->trans('Workstation'), '') . '</td>';
print '<td class="linecoltotalcost right">' . $form->textwithpicto($langs->trans('TotalCost'), '') . '</td>';
}
print '<td class="linecolqtyfrozen right">'.$form->textwithpicto($langs->trans('QtyFrozen'), $langs->trans("QuantityConsumedInvariable")).'</td>';
print '<td class="linecoldisablestockchange right">'.$form->textwithpicto($langs->trans('DisableStockChange'), $langs->trans('DisableStockChangeHelp')).'</td>';
print '<td class="linecollost right">'.$form->textwithpicto($langs->trans('ManufacturingEfficiency'), $langs->trans('ValueOfMeansLoss')).'</td>';
print '<td class="linecoledit" colspan="'.$colspan.'">&nbsp;</td>';
print '<td class="linecoledit" colspan="' . $colspan . '">&nbsp;</td>';
print '</tr>';
}
print '<tr class="pair nodrag nodrop nohoverpair'.(($nolinesbefore || $object->element == 'contrat') ? '' : ' liste_titre_create').'">';
@ -88,25 +105,23 @@ print '<td class="bordertop nobottom linecoldescription minwidth500imp">';
// Predefined product/service
if (isModEnabled("product") || isModEnabled("service")) {
if (!empty($conf->global->BOM_SUB_BOM)) {
if ($filtertype == 1) {
print $langs->trans("Service");
} elseif (!empty($conf->global->BOM_SUB_BOM)) {
print $langs->trans("Product");
}
echo '<span class="prod_entry_mode_predef">';
$filtertype = 0;
if (!empty($object->element) && $object->element == 'contrat' && empty($conf->global->STOCK_SUPPORT_SERVICES)) {
$filtertype = -1;
}
$statustoshow = -1;
if (!empty($conf->global->ENTREPOT_EXTRA_STATUS)) {
// hide products in closed warehouse, but show products for internal transfer
$form->select_produits(GETPOST('idprod', 'int'), 'idprod', $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, 'warehouseopen,warehouseinternal', GETPOST('combinations', 'array'));
$form->select_produits(GETPOST('idprod', 'int'), (($filtertype == 1) ? 'idprodservice' : 'idprod'), $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, 'warehouseopen,warehouseinternal', GETPOST('combinations', 'array'));
} else {
$form->select_produits(GETPOST('idprod', 'int'), 'idprod', $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, '', GETPOST('combinations', 'array'));
$form->select_produits(GETPOST('idprod', 'int'), (($filtertype == 1) ? 'idprodservice' : 'idprod'), $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, '', GETPOST('combinations', 'array'));
}
echo '</span>';
}
if (!empty($conf->global->BOM_SUB_BOM)) {
if (!empty($conf->global->BOM_SUB_BOM) && $filtertype!=1) {
print '<br><span class="opacitymedium">'.$langs->trans("or").'</span><br>'.$langs->trans("BOM");
// TODO Add component to select a BOM
$form->select_bom();
@ -118,35 +133,57 @@ $coldisplay++;
print '<td class="bordertop nobottom linecolqty right"><input type="text" size="2" name="qty" id="qty" class="flat right" value="'.(GETPOSTISSET("qty") ? GETPOST("qty", 'alpha', 2) : 1).'">';
print '</td>';
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
if ($filtertype != 1) {
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
$coldisplay++;
print '<td class="nobottom linecoluseunit left">';
print '</td>';
}
$coldisplay++;
print '<td class="nobottom linecoluseunit left">';
print '<td class="bordertop nobottom linecolqtyfrozen right"><input type="checkbox" name="qty_frozen" id="qty_frozen" class="flat right" value="1"' . (GETPOST("qty_frozen", 'alpha') ? ' checked="checked"' : '') . '>';
print '</td>';
$coldisplay++;
print '<td class="bordertop nobottom linecoldisablestockchange right"><input type="checkbox" name="disable_stock_change" id="disable_stock_change" class="flat right" value="1"' . (GETPOST("disable_stock_change", 'alpha') ? ' checked="checked"' : '') . '">';
print '</td>';
$coldisplay++;
print '<td class="bordertop nobottom nowrap linecollost right">';
print '<input type="text" size="2" name="efficiency" id="efficiency" class="flat right" value="' . ((GETPOSTISSET("efficiency") && $action == 'addline') ? GETPOST("efficiency", 'alpha') : 1) . '">';
print '</td>';
$coldisplay++;
print '<td class="bordertop nobottom nowrap linecolcost right">';
print '&nbsp;';
print '</td>';
} else {
$coldisplay++;
require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
$cUnit = new CUnits($this->db);
$fk_unit_default = $cUnit->getUnitFromCode('h', 'short_label', 'time');
print '<td class="bordertop nobottom nowrap linecolunit right">';
print $formproduct->selectMeasuringUnits("fk_unit", "time", $fk_unit_default, 0, 0);
print '</td>';
$coldisplay++;
print '<td class="bordertop nobottom nowrap linecolworkstation right">';
print '&nbsp;';
print '</td>';
$coldisplay++;
print '<td class="bordertop nobottom nowrap linecolcost right">';
print '&nbsp;';
print '</td>';
}
$coldisplay++;
print '<td class="bordertop nobottom linecolqtyfrozen right"><input type="checkbox" name="qty_frozen" id="qty_frozen" class="flat right" value="1"'.(GETPOST("qty_frozen", 'alpha') ? ' checked="checked"' : '').'>';
print '</td>';
$coldisplay += $colspan;
print '<td class="bordertop nobottom linecoledit center valignmiddle" colspan="' . $colspan . '">';
print '<input type="submit" class="button button-add" name="addline" id="addline" value="' . $langs->trans('Add') . '">';
print '</td>';
print '</tr>';
$coldisplay++;
print '<td class="bordertop nobottom linecoldisablestockchange right"><input type="checkbox" name="disable_stock_change" id="disable_stock_change" class="flat right" value="1"'.(GETPOST("disable_stock_change", 'alpha') ? ' checked="checked"' : '').'">';
print '</td>';
$coldisplay++;
print '<td class="bordertop nobottom nowrap linecollost right">';
print '<input type="text" size="2" name="efficiency" id="efficiency" class="flat right" value="'.((GETPOSTISSET("efficiency") && $action == 'addline') ?GETPOST("efficiency", 'alpha') : 1).'">';
print '</td>';
$coldisplay++;
print '<td class="bordertop nobottom nowrap linecolcost right">';
print '&nbsp;';
print '</td>';
$coldisplay += $colspan;
print '<td class="bordertop nobottom linecoledit center valignmiddle" colspan="'.$colspan.'">';
print '<input type="submit" class="button button-add" name="addline" id="addline" value="'.$langs->trans('Add').'">';
print '</td>';
print '</tr>';
if (is_object($objectline)) {
print $objectline->showOptionals($extrafields, 'edit', array('style'=>$bcnd[$var], 'colspan'=>$coldisplay), '', '', 1, 'line');
@ -175,6 +212,27 @@ jQuery(document).ready(function() {
}
}
});
//change unit selected if we change service selected
<?php if ($filtertype == 1) { ?>
$('#idprodservice').change(function(){
var idproduct = $(this).val();
$.ajax({
url : "<?php echo dol_buildpath('/bom/ajax/ajax.php', 1); ?>"
,type: 'POST'
,data: {
'action': 'getDurationUnitByProduct'
,'idproduct' : idproduct
}
}).done(function(data) {
console.log(data);
var data = JSON.parse(data);
$("#fk_unit").val(data).change();
});
});
<?php } ?>
});
</script>

View File

@ -31,6 +31,9 @@
* $inputalsopricewithtax (0 by default, 1 to also show column with unit price including tax)
*/
require_once DOL_DOCUMENT_ROOT."/product/class/html.formproduct.class.php";
// Protection to avoid direct call of template
if (empty($object) || !is_object($object)) {
print "Error, template page can't be called as URL";
@ -38,12 +41,16 @@ if (empty($object) || !is_object($object)) {
}
global $forceall;
global $forceall, $filtertype;
if (empty($forceall)) {
$forceall = 0;
}
if (empty($filtertype)) $filtertype = 0;
$formproduct = new FormProduct($object->db);
// Define colspan for the button 'Add'
$colspan = 3; // Columns: total ht + col edit + col delete
@ -108,28 +115,43 @@ if (($line->info_bits & 2) != 2) {
}
print '</td>';
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
if ($filtertype != 1) {
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
$coldisplay++;
print '<td class="nobottom linecoluseunit left">';
print '</td>';
}
$coldisplay++;
print '<td class="nobottom linecoluseunit left">';
print '<td class="nobottom linecolqtyfrozen right"><input type="checkbox" name="qty_frozen" id="qty_frozen" class="flat right" value="1"' . (GETPOSTISSET("qty_frozen") ? (GETPOST('qty_frozen', 'int') ? ' checked="checked"' : '') : ($line->qty_frozen ? ' checked="checked"' : '')) . '>';
print '</td>';
$coldisplay++;
print '<td class="nobottom linecoldisablestockchange right"><input type="checkbox" name="disable_stock_change" id="disable_stock_change" class="flat right" value="1"' . (GETPOSTISSET('disablestockchange') ? (GETPOST("disable_stock_change", 'int') ? ' checked="checked"' : '') : ($line->disable_stock_change ? ' checked="checked"' : '')) . '">';
print '</td>';
$coldisplay++;
print '<td class="nobottom nowrap linecollost right">';
print '<input type="text" size="2" name="efficiency" id="efficiency" class="flat right" value="' . $line->efficiency . '"></td>';
$coldisplay++;
print '<td class="nobottom nowrap linecolcostprice right">';
print '</td>';
} else {
$coldisplay++;
print '<td class="nobottom nowrap linecolunit right">';
print $formproduct->selectMeasuringUnits("fk_unit", "time", ($line->fk_unit) ? $line->fk_unit : '', 0, 0);
print '</td>';
$coldisplay++;
print '<td class="nobottom nowrap linecolworkstation right">';
print '</td>';
$coldisplay++;
print '<td class="nobottom nowrap linecolcostprice right">';
print '</td>';
}
$coldisplay++;
print '<td class="nobottom linecolqtyfrozen right"><input type="checkbox" name="qty_frozen" id="qty_frozen" class="flat right" value="1"'.(GETPOSTISSET("qty_frozen") ? (GETPOST('qty_frozen', 'int') ? ' checked="checked"' : '') : ($line->qty_frozen ? ' checked="checked"' : '')).'>';
print '</td>';
$coldisplay++;
print '<td class="nobottom linecoldisablestockchange right"><input type="checkbox" name="disable_stock_change" id="disable_stock_change" class="flat right" value="1"'.(GETPOSTISSET('disablestockchange') ? (GETPOST("disable_stock_change", 'int') ? ' checked="checked"' : '') : ($line->disable_stock_change ? ' checked="checked"' : '')).'">';
print '</td>';
$coldisplay++;
print '<td class="nobottom nowrap linecollost right">';
print '<input type="text" size="2" name="efficiency" id="efficiency" class="flat right" value="'.$line->efficiency.'"></td>';
$coldisplay++;
print '<td class="nobottom nowrap linecolcostprice right">';
print '</td>';
$coldisplay += $colspan;
print '<td class="nobottom linecoledit center valignmiddle" colspan="'.$colspan.'">';
$coldisplay += $colspan;

View File

@ -38,6 +38,10 @@ if (empty($object) || !is_object($object)) {
print "Error, template page can't be called as URL";
exit;
}
global $filtertype;
if (empty($filtertype)) $filtertype = 0;
print "<!-- BEGIN PHP TEMPLATE objectline_title.tpl.php -->\n";
@ -53,30 +57,42 @@ if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
// Product or sub-bom
print '<td class="linecoldescription">'.$langs->trans('Description');
if (!empty($conf->global->BOM_SUB_BOM)) {
if (!empty($conf->global->BOM_SUB_BOM) && $filtertype != 1) {
print ' &nbsp; <a id="show_all" href="#">'.img_picto('', 'folder-open', 'class="paddingright"').$langs->trans("ExpandAll").'</a>&nbsp;&nbsp;';
print '<a id="hide_all" href="#">'.img_picto('', 'folder', 'class="paddingright"').$langs->trans("UndoExpandAll").'</a>&nbsp;';
}
print '</td>';
// Qty
print '<td class="linecolqty right">'.$form->textwithpicto($langs->trans('Qty'), $langs->trans("QtyRequiredIfNoLoss")).'</td>';
print '<td class="linecolqty right">'.$form->textwithpicto($langs->trans('Qty'), ($filtertype != 1) ? $langs->trans("QtyRequiredIfNoLoss") : '').'</td>';
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="linecoluseunit left">'.$langs->trans('Unit').'</td>';
if ($filtertype != 1) {
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="linecoluseunit left">' . $langs->trans('Unit') . '</td>';
}
// Qty frozen
print '<td class="linecolqtyfrozen right">' . $form->textwithpicto($langs->trans('QtyFrozen'), $langs->trans("QuantityConsumedInvariable")) . '</td>';
// Disable stock change
print '<td class="linecoldisablestockchange right">' . $form->textwithpicto($langs->trans('DisableStockChange'), $langs->trans('DisableStockChangeHelp')) . '</td>';
// Efficiency
print '<td class="linecolefficiency right">' . $form->textwithpicto($langs->trans('ManufacturingEfficiency'), $langs->trans('ValueOfMeansLoss')) . '</td>';
// Cost
print '<td class="linecolcost right">'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).'</td>';
} else {
print '<td class="linecolunit right">' . $form->textwithpicto($langs->trans('Unit'), '').'</td>';
if ($conf->workstation->enabled) print '<td class="linecolworkstation right">' . $form->textwithpicto($langs->trans('DefaultWorkstation'), '') . '</td>';
// Cost
print '<td class="linecolcost right">'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCostService")).'</td>';
}
// Qty frozen
print '<td class="linecolqtyfrozen right">'.$form->textwithpicto($langs->trans('QtyFrozen'), $langs->trans("QuantityConsumedInvariable")).'</td>';
// Disable stock change
print '<td class="linecoldisablestockchange right">'.$form->textwithpicto($langs->trans('DisableStockChange'), $langs->trans('DisableStockChangeHelp')).'</td>';
// Efficiency
print '<td class="linecolefficiency right">'.$form->textwithpicto($langs->trans('ManufacturingEfficiency'), $langs->trans('ValueOfMeansLoss')).'</td>';
// Cost
print '<td class="linecolcost right">'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).'</td>';
print '<td class="linecoledit"></td>'; // No width to allow autodim

View File

@ -34,12 +34,17 @@
* $type, $text, $description, $line
*/
require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
// Protection to avoid direct call of template
if (empty($object) || !is_object($object)) {
print "Error, template page can't be called as URL";
exit;
}
global $filtertype;
if (empty($filtertype)) $filtertype = 0;
global $forceall, $senderissupplier, $inputalsopricewithtax, $outputalsopricetotalwithtax, $langs;
@ -60,7 +65,9 @@ if (empty($outputalsopricetotalwithtax)) {
}
// add html5 elements
$domData = ' data-element="'.$line->element.'"';
if ($filtertype == 1) $domData = ' data-element="'.$line->element.'service"';
else $domData = ' data-element="'.$line->element.'"';
$domData .= ' data-id="'.$line->id.'"';
$domData .= ' data-qty="'.$line->qty.'"';
$domData .= ' data-product_type="'.$line->product_type.'"';
@ -100,29 +107,54 @@ $coldisplay++;
echo price($line->qty, 0, '', 0, 0); // Yes, it is a quantity, not a price, but we just want the formating role of function price
print '</td>';
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="linecoluseunit nowrap left">';
$label = $tmpproduct->getLabelOfUnit('long');
if ($label !== '') {
print $langs->trans($label);
if ($filtertype != 1) {
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="linecoluseunit nowrap left">';
$label = $tmpproduct->getLabelOfUnit('long');
if ($label !== '') {
print $langs->trans($label);
}
print '</td>';
}
print '<td class="linecolqtyfrozen nowrap right">';
$coldisplay++;
echo $line->qty_frozen ? yn($line->qty_frozen) : '';
print '</td>';
print '<td class="linecoldisablestockchange nowrap right">';
$coldisplay++;
echo $line->disable_stock_change ? yn($line->disable_stock_change) : ''; // Yes, it is a quantity, not a price, but we just want the formating role of function price
print '</td>';
print '<td class="linecolefficiency nowrap right">';
$coldisplay++;
echo $line->efficiency;
print '</td>';
} else {
//Unité
print '<td class="linecolunit nowrap right">';
$coldisplay++;
if (!empty($line->fk_unit)) {
require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
$unit = new CUnits($this->db);
$unit->fetch($line->fk_unit);
print (isset($unit->label) ? "&nbsp;".$langs->trans(ucwords($unit->label))."&nbsp;" : '');
}
print '</td>';
//Poste de travail
if ($conf->workstation->enabled) {
$workstation = new Workstation($object->db);
$res = $workstation->fetch($tmpproduct->fk_default_workstation);
print '<td class="linecolunit nowrap right">';
$coldisplay++;
if ($res > 0) echo $workstation->getNomUrl();
print '</td>';
}
}
print '<td class="linecolqtyfrozen nowrap right">';
$coldisplay++;
echo $line->qty_frozen ? yn($line->qty_frozen) : '';
print '</td>';
print '<td class="linecoldisablestockchange nowrap right">';
$coldisplay++;
echo $line->disable_stock_change ? yn($line->disable_stock_change) : ''; // Yes, it is a quantity, not a price, but we just want the formating role of function price
print '</td>';
print '<td class="linecolefficiency nowrap right">';
$coldisplay++;
echo $line->efficiency;
print '</td>';
$total_cost = 0;
print '<td id="costline_'.$line->id.'" class="linecolcost nowrap right">';
$coldisplay++;

View File

@ -420,15 +420,16 @@ class CUnits // extends CommonObject
* Get unit from code
* @param string $code code of unit
* @param string $mode 0= id , short_label=Use short label as value, code=use code
* @param string $unit_type weight,size,surface,volume,qty,time...
* @return int <0 if KO, Id of code if OK
*/
public function getUnitFromCode($code, $mode = 'code')
public function getUnitFromCode($code, $mode = 'code', $unit_type = '')
{
if ($mode == 'short_label') {
return dol_getIdFromCode($this->db, $code, 'c_units', 'short_label', 'rowid');
return dol_getIdFromCode($this->db, $code, 'c_units', 'short_label', 'rowid', 0, ' AND unit_type = "'.$this->db->escape($unit_type).'"');
} elseif ($mode == 'code') {
return dol_getIdFromCode($this->db, $code, 'c_units', 'code', 'rowid');
return dol_getIdFromCode($this->db, $code, 'c_units', 'code', 'rowid', 0, ' AND unit_type = "'. $this->db->escape($unit_type) .'"');
}
return $code;

View File

@ -319,6 +319,27 @@ function convertSecondToTime($iSecond, $format = 'all', $lengthOfDay = 86400, $l
}
/** Convert duration to hour
*
* @param int $duration_value Duration value
* @param int $duration_unit Duration unit
* @return int $result
*/
function convertDurationtoHour($duration_value, $duration_unit)
{
$result = 0;
if ($duration_unit == 's') $result = $duration_value / 3600;
if ($duration_unit == 'i') $result = $duration_value / 60;
if ($duration_unit == 'h') $result = $duration_value;
if ($duration_unit == 'd') $result = $duration_value * 24;
if ($duration_unit == 'w') $result = $duration_value * 24 * 7;
if ($duration_unit == 'm') $result = $duration_value * 730.484;
if ($duration_unit == 'y') $result = $duration_value * 365 * 24;
return $result;
}
/**
* Generate a SQL string to make a filter into a range (for second of date until last second of date).
* This method allows to maje SQL request that will deal correctly the timezone of server.

View File

@ -8543,10 +8543,11 @@ function dol_osencode($str)
* @param string $fieldkey Field to search the key into
* @param string $fieldid Field to get
* @param int $entityfilter Filter by entity
* @param string $filters Filter on other fields
* @return int <0 if KO, Id of code if OK
* @see $langs->getLabelFromKey
*/
function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0)
function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
{
global $cache_codes;
@ -8568,6 +8569,9 @@ function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid =
if (!empty($entityfilter)) {
$sql .= " AND entity IN (".getEntity($tablename).")";
}
if ($filters) {
$sql .= $filters;
}
$resql = $db->query($sql);
if ($resql) {

View File

@ -147,6 +147,10 @@ ALTER TABLE llx_user CHANGE COLUMN note note_private text;
UPDATE llx_c_effectif SET code='EF101-500', libelle='101 - 500' WHERE code='EF100-500';
ALTER TABLE llx_product ADD COLUMN fk_default_workstation integer DEFAULT NULL;
ALTER TABLE llx_bom_bomline ADD COLUMN fk_unit integer DEFAULT NULL;
ALTER TABLE llx_rights_def ADD COLUMN tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
@ -170,3 +174,4 @@ create table llx_element_categorie
ALTER TABLE llx_element_categorie ADD UNIQUE INDEX idx_element_categorie_idx (fk_element, fk_categorie);
ALTER TABLE llx_element_categorie ADD CONSTRAINT fk_element_categorie_fk_categorie FOREIGN KEY (fk_categorie) REFERENCES llx_fk_categorie(rowid);

View File

@ -25,6 +25,7 @@ CREATE TABLE llx_bom_bomline(
qty_frozen smallint DEFAULT 0,
disable_stock_change smallint DEFAULT 0,
efficiency double(24,8) NOT NULL DEFAULT 1,
fk_unit integer NULL,
position integer NOT NULL DEFAULT 0
-- END MODULEBUILDER FIELDS
) ENGINE=innodb;

View File

@ -108,4 +108,5 @@ create table llx_product
mandatory_period tinyint DEFAULT 0, -- is used to signal to the user that the start and end dates are mandatory for this type of product the fk_product_type == 1 (service) (non-blocking action)
fk_default_bom integer DEFAULT NULL
fk_default_workstation integer DEFAULT NULL
)ENGINE=innodb;

View File

@ -82,6 +82,9 @@ ProductsToProduce=Produits à produire
UnitCost=Coût unitaire
TotalCost=Coût total
BOMTotalCost=Le coût de production de cette nomenclature basé sur chaque quantité et produit à consommer (utilise le prix de revient si défini, sinon le PMP si défini, sinon le meilleur prix d'achat)
BOMTotalCostService=Si le module "Poste de travail" est activé, alors le calcul est "quantité (convertie en heures) x thm du poste de travail", sinon "quantité (convertie en heures) x prix de revient du service"
BOMProductsList=Liste des composants
BOMServicesList=Liste des services
GoOnTabProductionToProduceFirst=Vous devez avoir la production pour clôturer un Ordre de Fabrication (voir onglet '%s'). Mais vous pouvez l'annuler.
ErrorAVirtualProductCantBeUsedIntoABomOrMo=Un kit ne peut pas être utilisé dans une Nomenclature ou un Ordre de fabrication.
Workstation=Poste de travail
@ -91,6 +94,7 @@ WorkstationSetup = Configuration du module Poste de travail
WorkstationSetupPage = Configuration du module Poste de travail
WorkstationList=Liste des postes de travail
WorkstationCreate=Ajouter un nouveau poste de travail
DefaultWorkstation=Poste de travail par défaut
ConfirmEnableWorkstation=Voulez-vous vraiment activer le poste de travail <b>%s</b>?
EnableAWorkstation=Activer le module Poste de travail
ConfirmDisableWorkstation=Voulez-vous vraiment désactiver la station de travail <b>%s</b>?

View File

@ -55,6 +55,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/modules/product/modules_product.class.php'
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
if (isModEnabled('propal')) {
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
@ -558,6 +559,7 @@ if (empty($reshook)) {
$object->duration_value = $duration_value;
$object->duration_unit = $duration_unit;
$object->fk_default_warehouse = GETPOST('fk_default_warehouse');
$object->fk_default_workstation = GETPOST('fk_default_workstation');
$object->seuil_stock_alerte = GETPOST('seuil_stock_alerte') ?GETPOST('seuil_stock_alerte') : 0;
$object->desiredstock = GETPOST('desiredstock') ?GETPOST('desiredstock') : 0;
$object->canvas = GETPOST('canvas');
@ -723,6 +725,7 @@ if (empty($reshook)) {
$object->status_batch = GETPOST('status_batch', 'aZ09');
$object->batch_mask = GETPOST('batch_mask', 'alpha');
$object->fk_default_warehouse = GETPOST('fk_default_warehouse');
$object->fk_default_workstation = GETPOST('fk_default_workstation');
// removed from update view so GETPOST always empty
/*
$object->seuil_stock_alerte = GETPOST('seuil_stock_alerte');
@ -1441,7 +1444,6 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
// Description (used in invoice, propal...)
print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
$doleditor = new DolEditor('desc', GETPOST('desc', 'restricthtml'), '', 160, 'dolibarr_details', '', false, true, getDolGlobalString('FCKEDITOR_ENABLE_PRODUCTDESC'), ROWS_4, '90%');
$doleditor->Create();
@ -1485,6 +1487,14 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
}
}
if ($type == 1 && $conf->workstation->enabled) {
// Default workstation
print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
print $formproduct->selectWorkstations($object->fk_default_workstation, 'fk_default_workstation', 1);
print '</td></tr>';
}
// Duration
if ($type == 1) {
print '<tr><td>'.$langs->trans("Duration").'</td><td>';
@ -2024,6 +2034,15 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
print '</td></tr>';
*/
}
if ($object->isService() && $conf->workstation->enabled) {
// Default workstation
print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
print $formproduct->selectWorkstations($object->fk_default_workstation, 'fk_default_workstation', 1);
print '</td></tr>';
}
/*
else
{
@ -2505,6 +2524,15 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
print '</td>';
}
if ($object->isService() && $conf->workstation->enabled) {
$workstation = new Workstation($db);
$res = $workstation->fetch($object->fk_default_workstation);
print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
print (!empty($workstation->id) ? $workstation->getNomUrl(1) : '');
print '</td>';
}
// Parent product.
if (!empty($conf->variants->enabled) && ($object->isProduct() || $object->isService())) {
$combination = new ProductCombination($db);

View File

@ -42,6 +42,7 @@ class FormProduct
// Cache arrays
public $cache_warehouses = array();
public $cache_lot = array();
public $cache_workstations = array();
/**
@ -172,6 +173,63 @@ class FormProduct
}
}
/**
* Load in cache array list of workstations
* If fk_product is not 0, we do not use cache
*
* @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
* @param array $exclude warehouses ids to exclude
* @param string $orderBy [='e.ref'] Order by
* @return int Nb of loaded lines, 0 if already loaded, <0 if KO
* @throws Exception
*/
public function loadWorkstations($fk_product = 0, $exclude = array(), $orderBy = 'w.ref')
{
global $conf, $langs;
if (empty($fk_product) && count($this->cache_workstations)) {
return 0; // Cache already loaded and we do not want a list with information specific to a product
}
$sql = "SELECT w.rowid, w.ref as ref, w.label as label, w.type, w.nb_operators_required,w.thm_operator_estimated,w.thm_machine_estimated";
$sql .= " FROM ".$this->db->prefix()."workstation_workstation as w";
$sql .= " WHERE 1 = 1";
if (!empty($fk_product) && $fk_product > 0) {
$sql .= " AND w.fk_product = ".((int) $fk_product);
}
$sql .= " AND w.entity IN (".getEntity('workstation').")";
if (is_array($exclude) && !empty($exclude)) {
$sql .= ' AND w.rowid NOT IN('.$this->db->sanitize(implode(',', $exclude)).')';
}
$sql .= " ORDER BY ".$orderBy;
dol_syslog(get_class($this).'::loadWorkstations', LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql) {
$num = $this->db->num_rows($resql);
$i = 0;
while ($i < $num) {
$obj = $this->db->fetch_object($resql);
$this->cache_workstations[$obj->rowid]['id'] = $obj->rowid;
$this->cache_workstations[$obj->rowid]['ref'] = $obj->ref;
$this->cache_workstations[$obj->rowid]['label'] = $obj->label;
$this->cache_workstations[$obj->rowid]['type'] = $obj->type;
$this->cache_workstations[$obj->rowid]['nb_operators_required'] = $obj->nb_operators_required;
$this->cache_workstations[$obj->rowid]['thm_operator_estimated'] = $obj->thm_operator_estimated;
$this->cache_workstations[$obj->rowid]['thm_machine_estimated'] = $obj->thm_machine_estimated;
$i++;
}
return $num;
} else {
dol_print_error($this->db);
return -1;
}
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return full path to current warehouse in $tab (recursive function)
@ -320,6 +378,104 @@ class FormProduct
return $out;
}
/**
* Return list of workstations
*
* @param string|int $selected Id of preselected warehouse ('' or '-1' for no value, 'ifone' and 'ifonenodefault' = select value if one value otherwise no value, '-2' to use the default value from setup)
* @param string $htmlname Name of html select html
* @param int $empty 1=Can be empty, 0 if not
* @param int $disabled 1=Select is disabled
* @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
* @param string $empty_label Empty label if needed (only if $empty=1)
* @param int $forcecombo 1=Force combo iso ajax select2
* @param array $events Events to add to select2
* @param string $morecss Add more css classes to HTML select
* @param array $exclude Warehouses ids to exclude
* @param int $showfullpath 1=Show full path of name (parent ref into label), 0=Show only ref of current warehouse
* @param string $orderBy [='e.ref'] Order by
* @return string HTML select
*
* @throws Exception
*/
public function selectWorkstations($selected = '', $htmlname = 'idworkstations', $empty = 0, $disabled = 0, $fk_product = 0, $empty_label = '', $forcecombo = 0, $events = array(), $morecss = 'minwidth200', $exclude = array(), $showfullpath = 1, $orderBy = 'e.ref')
{
global $conf, $langs, $user, $hookmanager;
dol_syslog(get_class($this)."::selectWorkstations $selected, $htmlname, $empty, $disabled, $fk_product, $empty_label, $forcecombo, $morecss", LOG_DEBUG);
$out = '';
if (!empty($fk_product) && $fk_product > 0) {
$this->cache_workstations = array();
}
$this->loadWorkstations($fk_product);
$nbofworkstations = count($this->cache_workstations);
if ($conf->use_javascript_ajax && !$forcecombo) {
include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
$comboenhancement = ajax_combobox($htmlname, $events);
$out .= $comboenhancement;
}
if (strpos($htmlname, 'search_') !== 0) {
if (empty($user->fk_workstation) || $user->fk_workstation == -1) {
if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WORKSTATION)) {
$selected = $conf->global->MAIN_DEFAULT_WORKSTATION;
}
} else {
if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WORKSTATION)) {
$selected = $user->fk_workstation;
}
}
}
$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled' : '').' id="'.$htmlname.'" name="'.($htmlname.($disabled ? '_disabled' : '')).'">';
if ($empty) {
$out .= '<option value="-1">'.($empty_label ? $empty_label : '&nbsp;').'</option>';
}
foreach ($this->cache_workstations as $id => $arraytypes) {
$label = $arraytypes['label'];
$out .= '<option value="'.$id.'"';
if ($selected == $id || (preg_match('/^ifone/', $selected) && $nbofworkstations == 1)) {
$out .= ' selected';
}
$out .= ' data-html="'.dol_escape_htmltag($label).'"';
$out .= '>';
$out .= $label;
$out .= '</option>';
}
$out .= '</select>';
if ($disabled) {
$out .= '<input type="hidden" name="'.$htmlname.'" value="'.(($selected > 0) ? $selected : '').'">';
}
$parameters = array(
'selected' => $selected,
'htmlname' => $htmlname,
'filterstatus' => $filterstatus,
'empty' => $empty,
'disabled ' => $disabled,
'fk_product' => $fk_product,
'empty_label' => $empty_label,
'forcecombo' => $forcecombo,
'events' => $events,
'morecss' => $morecss,
'exclude' => $exclude,
'showfullpath' => $showfullpath,
'orderBy' => $orderBy
);
$reshook = $hookmanager->executeHooks('selectWorkstations', $parameters, $this);
if ($reshook > 0) {
$out = $hookmanager->resPrint;
} elseif ($reshook == 0) {
$out .= $hookmanager->resPrint;
}
return $out;
}
/**
* Display form to select warehouse
*

View File

@ -238,6 +238,11 @@ class Product extends CommonObject
*/
public $duration_value;
/*
* Service Workstation
*/
public $fk_default_workstation;
/**
* Exoiration unit
*/
@ -1146,6 +1151,7 @@ class Product extends CommonObject
$sql .= ", volume = ".($this->volume != '' ? "'".$this->db->escape($this->volume)."'" : 'null');
$sql .= ", volume_units = ".($this->volume_units != '' ? "'".$this->db->escape($this->volume_units)."'" : 'null');
$sql .= ", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? $this->db->escape($this->fk_default_warehouse) : 'null');
$sql .= ", fk_default_workstation = ".($this->fk_default_workstation > 0 ? $this->db->escape($this->fk_default_workstation) : 'null');
$sql .= ", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (float) $this->seuil_stock_alerte : 'null');
$sql .= ", description = '".$this->db->escape($this->description)."'";
$sql .= ", url = ".($this->url ? "'".$this->db->escape($this->url)."'" : 'null');
@ -2287,7 +2293,7 @@ class Product extends CommonObject
$sql = "SELECT p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note as note_private, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc,";
$sql .= " p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly as tva_npr, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell,";
$sql .= " p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
$sql .= " p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
$sql .= " p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
$sql .= " p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period,";
if (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
@ -2349,7 +2355,7 @@ class Product extends CommonObject
if ($separatedStock) {
$sql .= " GROUP BY p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc,";
$sql .= " p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell,";
$sql .= " p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
$sql .= " p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
$sql .= " p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
$sql .= " p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished,";
if (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
@ -2448,6 +2454,7 @@ class Product extends CommonObject
$this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
$this->fk_default_warehouse = $obj->fk_default_warehouse;
$this->fk_default_workstation = $obj->fk_default_workstation;
$this->seuil_stock_alerte = $obj->seuil_stock_alerte;
$this->desiredstock = $obj->desiredstock;
$this->stock_reel = $obj->stock;