Merge pull request #18503 from atm-adrien/NEW_develop_sub_BOM

NEW : Sub bill of materials
This commit is contained in:
Laurent Destailleur 2021-10-23 18:26:46 +02:00 committed by GitHub
commit 7f19682724
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 226 additions and 3 deletions

View File

@ -0,0 +1,28 @@
<?php
require '../../main.inc.php';
$action = GETPOST('action', 'alphanohtml');
$select_product_val = GETPOST('select_product_val', 'int');
$current_bom_id = GETPOST('current_bom_id', 'int');
global $db;
switch ($action) {
case 'select_BOM':
//Selection of nomenclatures corresponding to the selected product
$sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product, p.label AS product_label FROM '.MAIN_DB_PREFIX.'bom_bom AS b ';
$sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'product AS p ON b.fk_product=p.rowid';
$sql.= ' WHERE fk_product='.(int) $select_product_val.' AND b.rowid<>'. (int) $current_bom_id;
$resql = $db->query($sql);
if ($resql && $db->num_rows($resql) > 0) {
$options = array();
$cpt=0;
while ($obj = $db->fetch_object($resql)) {
$options[$obj->rowid] = $obj->ref.' - '.$obj->label;
$cpt++;
}
print json_encode($options);
}
break;
}

View File

@ -149,6 +149,7 @@ if (empty($reshook)) {
// Set if we used free entry or predefined product
$idprod = (int) GETPOST('idprod', 'int');
$bom_child = (int) GETPOST('bom_select', 'int');
$qty = price2num(GETPOST('qty', 'alpha'), 'MS');
$qty_frozen = price2num(GETPOST('qty_frozen', 'alpha'), 'MS');
$disable_stock_change = GETPOST('disable_stock_change', 'int');
@ -172,6 +173,7 @@ if (empty($reshook)) {
$bomline = new BOMLine($db);
$bomline->fk_bom = $id;
$bomline->fk_product = $idprod;
$bomline->fk_bom_child = $bom_child;
$bomline->qty = $qty;
$bomline->qty_frozen = (int) $qty_frozen;
$bomline->disable_stock_change = (int) $disable_stock_change;
@ -571,9 +573,78 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
print '</table>';
}
?>
<script>
let select_product_val;
let current_bom_id = <?php echo $object->id?>;
//On change on the bom select
$('#idprod').on('change', function () {
select_product_val = $('#idprod').select2().val();
//Ajax to set all options without reloading the page
$.ajax({
url: 'script/interface.php'
, method: 'POST'
, dataType: 'text'
, data: {
action: 'select_BOM'
, select_product_val: select_product_val
, current_bom_id: current_bom_id
}
}).done(function (data) {
//To remove all options of the bom select on change
$('#bom_select').get(0).length = 0;
//To set options for the bom select on change
let options = JSON.parse(data)
for (let key in options) {
let opt = new Option(options[key], key);
$('#bom_select').append(opt)
}
})
})
</script>
<?php
print '</div>';
print "</form>\n";
?>
<script type="text/javascript" language="javascript">
$(document).ready(function() {
$(".collapse_bom").click(function() {
var id_bom_line = $(this).attr('id').replace('collapse-', '');
if($(this).text().indexOf('+') > 0) {
$('[parentid="'+ id_bom_line +'"]').show();
$(this).html('(-)&nbsp;');
}
else {
$('[parentid="'+ id_bom_line +'"]').hide();
$(this).html('(+)&nbsp;');
}
return false;
});
//To Show all the sub bom lines
$("#show_all").click(function() {
$("[class^=sub_bom_lines]").show();
$("[class^=collapse_bom]").html('(-)&nbsp;');
return false;
});
//To Hide all the sub bom lines
$("#hide_all").click(function() {
$("[class^=sub_bom_lines]").hide();
$("[class^=collapse_bom]").html('(+)&nbsp;');
return false;
});
});
</script>
<?php
}

View File

@ -1139,6 +1139,7 @@ class BOMLine extends CommonObjectLine
'rowid' => array('type'=>'integer', 'label'=>'LineID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
'fk_bom' => array('type'=>'integer:BillOfMaterials:societe/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1,),
'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
'fk_bom_child' => array('type'=>'integer:BOM:bom/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>-1, 'position'=>40, 'notnull'=>-1,),
'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
'qty' => array('type'=>'double(24,8)', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'position'=>100, 'notnull'=>1, 'isameasure'=>'1',),
'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
@ -1163,6 +1164,11 @@ class BOMLine extends CommonObjectLine
*/
public $fk_product;
/**
* @var int Id of parent bom
*/
public $fk_bom_child;
/**
* @var string description
*/

View File

@ -61,6 +61,8 @@ if ($nolinesbefore) {
print '<td class="linecoldescription minwidth500imp">';
print '<div id="add"></div><span class="hideonsmartphone">'.$langs->trans('AddNewLine').'</span>';
print '</td>';
// Linked BOM
print '<td class="linecolBOM">'.$langs->trans('BOM').'</td>';
print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="linecoluseunit left">';
@ -107,6 +109,10 @@ if (!empty($conf->product->enabled) || !empty($conf->service->enabled)) {
echo '</span>';
}
$coldisplay++;
print '<td class="bordertop nobottom linecolbom">';
print '<select id="bom_select" name="bom_select"><options value="-1"></options></select>';
print '</td>';
$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).'">';

View File

@ -97,6 +97,8 @@ print '</td>';
*/
$coldisplay++;
// For BOM
print '<td></td>';
print '<td class="nobottom linecolqty right">';
if (($line->info_bits & 2) != 2) {

View File

@ -43,6 +43,8 @@ print "<!-- BEGIN PHP TEMPLATE objectline_title.tpl.php -->\n";
print "<thead>\n";
print '<tr class="liste_titre nodrag nodrop">';
print '<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;';
// Adds a line numbering column
if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
@ -52,6 +54,9 @@ if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
// Description
print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
// Linked BOM
print '<td class="linecolBOM">'.$langs->trans('BOM').'</td>';
// Qty
print '<td class="linecolqty right">'.$form->textwithpicto($langs->trans('Qty'), $langs->trans("QtyRequiredIfNoLoss")).'</td>';

View File

@ -80,9 +80,22 @@ print '<div id="line_'.$line->id.'"></div>';
$coldisplay++;
$tmpproduct = new Product($object->db);
$tmpproduct->fetch($line->fk_product);
$tmpbom = new BOM($object->db);
$res = $tmpbom->fetch($line->fk_bom_child);
if (!empty($tmpbom->id)) {
print '<a class="collapse_bom" id="collapse-'.$line->id.'" href="#">' . (empty($conf->global->BOM_SHOW_ALL_BOM_BY_DEFAULT) ? '(+)' : '(-)') . '&nbsp;</a>';
}
print $tmpproduct->getNomUrl(1);
print ' - '.$tmpproduct->label;
print '</td>';
// To show BOM links in the list
if ($res > 0) {
print '<td id="bom_id">'.$tmpbom->getNomUrl(1).'</td>';
} else {
print '<td id="bom_id">&nbsp;</td>';
}
print '<td class="linecolqty nowrap right">';
$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
@ -111,7 +124,8 @@ $coldisplay++;
echo $line->efficiency;
print '</td>';
print '<td class="linecolcost nowrap right">';
$total_cost = 0;
print '<td id="costline_'.$line->id.'" class="linecolcost nowrap right">';
$coldisplay++;
echo price($line->total_cost);
print '</td>';
@ -166,6 +180,93 @@ if ($action == 'selectlines') {
print '</tr>';
// Select of all the sub-BOM lines
$sql = 'SELECT rowid, fk_bom_child, fk_product FROM '.MAIN_DB_PREFIX.'bom_bomline AS bl';
$sql.= ' WHERE fk_bom ='. (int) $tmpbom->id;
$resql = $object->db->query($sql);
if ($resql) {
// Loop on all the sub-BOM lines if they exist
while ($obj = $object->db->fetch_object($resql)) {
$sub_bom_product = new Product($object->db);
$sub_bom_product->fetch($obj->fk_product);
$sub_bom = new BOM($object->db);
$sub_bom->fetch($obj->fk_bom_child);
$sub_bom_line = new BOMLine($object->db);
$sub_bom_line->fetch($obj->rowid);
//If hidden conf is set, we show directly all the sub-BOM lines
if (empty($conf->global->BOM_SHOW_ALL_BOM_BY_DEFAULT)) {
print '<tr style="display:none" class="sub_bom_lines" parentid="'.$line->id.'">';
} else {
print '<tr class="sub_bom_lines" parentid="'.$line->id.'">';
}
// Product
print '<td style="padding-left: 5%" id="sub_bom_product_'.$sub_bom_line->id.'">'.$sub_bom_product->getNomUrl(1).'</td>';
// Sub-BOM
if ($sub_bom_line->fk_bom_child > 0) {
print '<td id="sub_bom_bom_'.$sub_bom_line->id.'">'.$sub_bom->getNomUrl(1).'</td>';
} else {
print '<td id="sub_bom_bom_'.$sub_bom_line->id.'">&nbsp;</td>';
}
// Qty
print '<td class="linecolqty nowrap right" id="sub_bom_qty_'.$sub_bom_line->id.'">'.price($sub_bom_line->qty * $line->qty, 0, '', 0, 0).'</td>';
if ($sub_bom_line->qty_frozen > 0) {
print '<td class="linecolqtyfrozen nowrap right" id="sub_bom_qty_frozen_'.$sub_bom_line->id.'">'.$sub_bom_line->qty_frozen.'</td>';
} else {
print '<td class="linecolqtyfrozen nowrap right" id="sub_bom_qty_frozen_'.$sub_bom_line->id.'">&nbsp;</td>';
}
// Disable stock change
if ($sub_bom_line->disable_stock_change > 0) {
print '<td class="linecoldisablestockchange nowrap right" id="sub_bom_stock_change_'.$sub_bom_line->id.'">'.$sub_bom_line->disable_stock_change.'</td>';
} else {
print '<td class="linecoldisablestockchange nowrap right" id="sub_bom_stock_change_'.$sub_bom_line->id.'">&nbsp;</td>';
}
// Efficiency
print '<td class="linecolefficiency nowrap right" id="sub_bom_efficiency_'.$sub_bom_line->id.'">'.$sub_bom_line->efficiency.'</td>';
// Cost price if it's defined
if ($sub_bom_product->cost_price > 0) {
print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'">'.price($sub_bom_product->cost_price * $line->qty).'</td>';
$total_cost.= $sub_bom_product->cost_price * $line->qty;
} elseif ($sub_bom_product->pmp > 0) { // PMP if cost price isn't defined
print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'">'.price($sub_bom_product->pmp * $line->qty).'</td>';
$total_cost.= $sub_bom_product->pmp * $line->qty;
} else { // Minimum purchase price if cost price and PMP aren't defined
$sql_supplier_price = 'SELECT MIN(price) AS min_price FROM '.MAIN_DB_PREFIX.'product_fournisseur_price';
$sql_supplier_price.= ' WHERE fk_product = '. (int) $sub_bom_product->id;
$resql_supplier_price = $object->db->query($sql_supplier_price);
if ($resql_supplier_price) {
$obj = $object->db->fetch_object($resql_supplier_price);
print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'">'.price($obj->min_price * $line->qty).'</td>';
$total_cost+= $obj->min_price * $line->qty;
}
}
print '<td></td>';
print '<td></td>';
print '<td></td>';
}
}
// Replace of the total_cost value by the sum of all sub-BOM lines total_cost
if ($total_cost > 0) {
$line->total_cost = price($total_cost);
?>
<script>
$('#costline_<?php echo $line->id?>').html("<?php echo "".price($total_cost)?>");
</script>
<?php
}
//Line extrafield
if (!empty($extrafields)) {
print $line->showOptionals($extrafields, 'view', array('style'=>'class="drag drop oddeven"', 'colspan'=>$coldisplay), '', '', 1, 'line');

View File

@ -104,4 +104,6 @@ HumanMachine=Human / Machine
WorkstationArea=Workstation area
Machines=Machines
THMEstimatedHelp=This rate makes it possible to define a forecast cost of the item
BOM=Bill Of Materials
CollapseBOMHelp=You can define the default display of the details of the nomenclature in the configuration of the BOM module
MOAndLines=Manufacturing Orders and lines

View File

@ -32,7 +32,7 @@ ValueOfMeansLossForProductProduced=Une valeur de 0,95 signifie une moyenne de 5%
DeleteBillOfMaterials=Supprimer la nomenclature
DeleteMo=Supprimer l'ordre de fabrication
ConfirmDeleteBillOfMaterials=Êtes-vous sûr de vouloir supprimer cette nomenclature?
ConfirmDeleteMo=Are you sure you want to delete this Manufacturing Order?
ConfirmDeleteMo=Êtes-vous sûr de vouloir supprimer cette nomenclature?
MenuMRP=Ordres de fabrication
NewMO=Nouvel Ordre de fabrication
QtyToProduce=Quantité à produire
@ -74,7 +74,7 @@ NoStockChangeOnServices=Aucune variation de stock sur les services
ProductQtyToConsumeByMO=Quantité de produit restant à consommer par OF ouvert
ProductQtyToProduceByMO=Quantités restant à produire avec les OF ouverts
AddNewConsumeLines=Ajouter une nouvelle ligne à consommer
AddNewProduceLines=Add new line to produce
AddNewProduceLines=Ajouter une nouvelle ligne à produire
ProductsToConsume=Produits à consommer
ProductsToProduce=Produits à produire
UnitCost=Coût unitaire
@ -105,3 +105,5 @@ WorkstationArea=Espace Poste de travail
Machines=Machines
THMEstimatedHelp=Ce taux permet de définir un coût prévisionnel de l'article
MOAndLines=Ordres de fabrication et lignes
BOM=Nomenclature
CollapseBOMHelp=Vous pouvez définir l'affichage par défaut du détail des nomenclature dans la configuration du module "Nomenclature Produits"