diff --git a/htdocs/admin/stock.php b/htdocs/admin/stock.php
index 6b2c626da39..0592b738fdd 100644
--- a/htdocs/admin/stock.php
+++ b/htdocs/admin/stock.php
@@ -87,6 +87,9 @@ if($action)
if($action == 'STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT') {
$res = dolibarr_set_const($db, "STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT", GETPOST('STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT','alpha'),'chaine',0,'',$conf->entity);
}
+ if($action == 'INDEPENDANT_SUBPRODUCT_STOCK') {
+ $res = dolibarr_set_const($db, "INDEPENDANT_SUBPRODUCT_STOCK", GETPOST('INDEPENDANT_SUBPRODUCT_STOCK','alpha'),'chaine',0,'',$conf->entity);
+ }
if (! $res > 0) $error++;
@@ -339,9 +342,29 @@ print '';
print "\n";
print "\n";
print '
';
-print '';
-print '
';
+/* I keep the option/feature, but hidden to end users for the moment. If feature is used by module, no need to have users see it.
+If not used by a module, I still need to understand in which case user may need this now we can set rule on product page.
+if ($conf->global->PRODUIT_SOUSPRODUITS)
+{
+ $var=!$var;
+
+ print "
";
+ print '| '.$langs->trans("IndependantSubProductStock").' | ';
+
+ print '';
+ print "';
+ print " | \n";
+ print "
\n";
+}
+*/
+
+print '';
llxFooter();
diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang
index b896dc955e6..3d52da2cd03 100755
--- a/htdocs/langs/en_US/products.lang
+++ b/htdocs/langs/en_US/products.lang
@@ -250,4 +250,7 @@ PriceExpressionEditorHelp3=In both product/service and supplier prices there are
PriceExpressionEditorHelp4=In product/service price only: #supplier_min_price#
In supplier prices only: #supplier_quantity# and #supplier_tva_tx#
PriceMode=Price mode
PriceNumeric=Number
-DefaultPrice=Default price
\ No newline at end of file
+DefaultPrice=Default price
+ComposedProductDecreaseStock=Decrease Stock for sub-product
+ComposedProduct=Sub-product
+MinSupplierPrice=Minimun supplier price
diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang
index 10fcf353fd4..7025176c9f1 100644
--- a/htdocs/langs/en_US/stocks.lang
+++ b/htdocs/langs/en_US/stocks.lang
@@ -47,6 +47,7 @@ PMPValue=Weighted average price
PMPValueShort=WAP
EnhancedValueOfWarehouses=Warehouses value
UserWarehouseAutoCreate=Create a warehouse automatically when creating a user
+IndependantSubProductStock=Product stock and subproduct stock are independant
QtyDispatched=Quantity dispatched
QtyDispatchedShort=Qty dispatched
QtyToDispatchShort=Qty to dispatch
diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php
index 3f3786016e5..fe67938766d 100755
--- a/htdocs/product/class/product.class.php
+++ b/htdocs/product/class/product.class.php
@@ -2306,6 +2306,40 @@ class Product extends CommonObject
}
}
+ /**
+ * Modify composed product
+ *
+ * @param int $id_pere Id of master product
+ * @param int $id_fils Id of linked product
+ * @param int $qty Quantity
+ * @param int $incdec increase/descrease stock or not
+ * * @return int < 0 if KO, > 0 if OK
+ */
+ function update_sousproduit($id_pere, $id_fils,$qty, $incdec=1)
+ {
+ // Clean parameters
+ if (! is_numeric($id_pere)) $id_pere=0;
+ if (! is_numeric($id_fils)) $id_fils=0;
+ if (! is_numeric($incdec)) $incdec=1;
+ if (! is_numeric($qty)) $qty=1;
+
+ $sql = 'UPDATE '.MAIN_DB_PREFIX.'product_association SET ';
+ $sql.= 'qty='.$qty;
+ $sql.= ',incdec='.$incdec;
+ $sql .= ' WHERE fk_product_pere='.$id_pere.' AND fk_product_fils='.$id_fils;
+
+ if (!$this->db->query($sql))
+ {
+ dol_print_error($this->db);
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ }
+
/**
* Retire le lien entre un sousproduit et un produit/service
*
@@ -2633,6 +2667,8 @@ class Product extends CommonObject
$nb=(! empty($desc_pere[1]) ? $desc_pere[1] :'');
$type=(! empty($desc_pere[2]) ? $desc_pere[2] :'');
$label=(! empty($desc_pere[3]) ? $desc_pere[3] :'');
+ $incdec=!empty($desc_pere[4]) ? $desc_pere[4] : 0;
+
if ($multiply < 1) $multiply=1;
//print "XXX We add id=".$id." - label=".$label." - nb=".$nb." - multiply=".$multiply." fullpath=".$compl_path.$label."\n";
@@ -2649,7 +2685,8 @@ class Product extends CommonObject
'fullpath'=>$compl_path.$label, // Label
'type'=>$type, // Nb of units that compose parent product
'desiredstock'=>$this->desiredstock,
- 'level'=>$level
+ 'level'=>$level,
+ 'incdec'=>$incdec
);
// Recursive call if there is childs to child
@@ -2798,7 +2835,7 @@ class Product extends CommonObject
*/
function getChildsArbo($id)
{
- $sql = "SELECT p.rowid, p.label as label, pa.qty as qty, pa.fk_product_fils as id, p.fk_product_type";
+ $sql = "SELECT p.rowid, p.label as label, pa.qty as qty, pa.fk_product_fils as id, p.fk_product_type, pa.incdec";
$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
$sql.= ", ".MAIN_DB_PREFIX."product_association as pa";
$sql.= " WHERE p.rowid = pa.fk_product_fils";
@@ -2812,7 +2849,13 @@ class Product extends CommonObject
$prods = array();
while ($rec = $this->db->fetch_array($res))
{
- $prods[$rec['rowid']]= array(0=>$rec['id'],1=>$rec['qty'],2=>$rec['fk_product_type'],3=>$this->db->escape($rec['label']));
+ $prods[$rec['rowid']]= array(
+ 0=>$rec['id'],
+ 1=>$rec['qty'],
+ 2=>$rec['fk_product_type'],
+ 3=>$this->db->escape($rec['label']),
+ 4=>$rec['incdec']
+ );
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty'],2=>$rec['fk_product_type']);
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty']);
$listofchilds=$this->getChildsArbo($rec['id']);
diff --git a/htdocs/product/composition/card.php b/htdocs/product/composition/card.php
index 12553ada59a..9efa7772cb0 100644
--- a/htdocs/product/composition/card.php
+++ b/htdocs/product/composition/card.php
@@ -109,6 +109,19 @@ $cancel <> $langs->trans("Cancel") &&
exit;
}
}
+else if($action==='save_composed_product') {
+
+ $TProduct = GETPOST('TProduct', 'array');
+ if(!empty($TProduct)) {
+
+ foreach ($TProduct as $id_product => $row) {
+ $product->update_sousproduit($id, $id_product,$row['qty'], isset($row['incdec']) ? 1 : 0 );
+ }
+
+ }
+
+
+}
if ($cancel == $langs->trans("Cancel"))
{
@@ -175,97 +188,6 @@ dol_fiche_head($head, 'subproduct', $titre, 0, $picto);
if ($id > 0 || ! empty($ref))
{
-/* if ($result)
- {
- if ($action <> 'edit' && $action <> 'search' && $action <> 're-edit')
- {
- // mode visu
-
- print '';
-
- print "";
-
- $nblignes=6;
- if ($product->isproduct() && ! empty($conf->stock->enabled)) $nblignes++;
- if ($product->isservice()) $nblignes++;
-
- // Reference
- print '| '.$langs->trans("Ref").' | ';
- print $form->showrefnav($product,'ref','',1,'ref');
- print ' |
';
-
- // Libelle
- print '| '.$langs->trans("Label").' | '.$product->libelle.' | ';
- print '
';
-
- // Number of subproducts
- $prodsfather = $product->getFather(); // Parent Products
- $product->get_sousproduits_arbo();
- $prods_arbo=$product->get_arbo_each_prod();
- $nbofsubproducts=count($prods_arbo);
- print '| '.$langs->trans("AssociatedProductsNumber").' | ';
- print $form->textwithpicto($nbofsubproducts, $langs->trans('IfZeroItIsNotAVirtualProduct'));
- print ' | ';
-
- dol_fiche_end();
-
-
- // List of products into this virtual product
- if (count($prods_arbo) > 0)
- {
- print '
';
- print ''.$langs->trans("ProductAssociationList").' ';
- print '';
- foreach($prods_arbo as $value)
- {
- $productstatic->id=$value['id'];
- $productstatic->type=$value['type'];
- $productstatic->ref=$value['fullpath'];
- if (! empty($conf->stock->enabled)) $productstatic->load_stock();
- //var_dump($value);
- //print ''.$productstatic->ref.' ';
- //print $productstatic->getNomUrl(1).' ';
- //print $value[0]; // This contains a tr line.
- print '';
- //print '| '.$productstatic->getNomUrl(1,'composition').' ('.$value['nb'].($value['nb_total'] > $value['nb']?'->'.$value['nb_total']:'').')     | ';
- print ''.$productstatic->getNomUrl(1,'composition').' ('.$value['nb'].')     | ';
- if (! empty($conf->stock->enabled)) print ''.$langs->trans("Stock").' : '.$productstatic->stock_reel.' | ';
- print ' ';
- }
- print ' ';
- print ' |
';
- }
-
- // Number of parent virtual products
- print '| '.$langs->trans("ParentProductsNumber").' | ';
- print $form->textwithpicto(count($prodsfather), $langs->trans('IfZeroItIsNotUsedByVirtualProduct'));
- print ' | ';
-
- if (count($prodsfather) > 0)
- {
- print '
';
- print ''.$langs->trans("ProductParentList").' ';
- print '';
- foreach($prodsfather as $value)
- {
- $idprod= $value["id"];
- $productstatic->id=$idprod;// $value["id"];
- $productstatic->type=$value["fk_product_type"];
- $productstatic->ref=$value['label'];
- print '';
- print '| '.$productstatic->getNomUrl(1,'composition').' | ';;
- print ' ';
- }
- print ' ';
- print ' |
';
- }
-
- print "
\n";
-
- dol_fiche_end();
- }
- }
-*/
/*
* Fiche en mode edition
*/
@@ -333,20 +255,43 @@ if ($id > 0 || ! empty($ref))
$atleastonenotdefined=0;
print '';
print $langs->trans("ProductAssociationList").' ';
- print '';
+
+ print '';
+
print '';
}
// Number of parent virtual products
- print '| '.$langs->trans("ParentProductsNumber").' | ';
+ print ' | | '.$langs->trans("ParentProductsNumber").' | ';
print $form->textwithpicto(count($prodsfather), $langs->trans('IfZeroItIsNotUsedByVirtualProduct'));
print ' | ';
diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php
index f175d75db6f..39dd2ff5f67 100644
--- a/htdocs/product/stock/class/mouvementstock.class.php
+++ b/htdocs/product/stock/class/mouvementstock.class.php
@@ -292,7 +292,7 @@ class MouvementStock extends CommonObject
}
// Add movement for sub products (recursive call)
- if (! $error && ! empty($conf->global->PRODUIT_SOUSPRODUITS))
+ if (! $error && ! empty($conf->global->PRODUIT_SOUSPRODUITS) && empty($conf->global->INDEPENDANT_SUBPRODUCT_STOCK))
{
$error = $this->_createSubProduct($user, $fk_product, $entrepot_id, $qty, $type, 0, $label, $inventorycode); // we use 0 as price, because pmp is not changed for subproduct
}
@@ -341,8 +341,7 @@ class MouvementStock extends CommonObject
$sql = "SELECT fk_product_pere, fk_product_fils, qty";
$sql.= " FROM ".MAIN_DB_PREFIX."product_association";
$sql.= " WHERE fk_product_pere = ".$idProduct;
- // TODO Select only subproduct with incdec tag
- //$sql.= " AND incdec = 1";
+ $sql.= " AND incdec = 1";
dol_syslog(get_class($this)."::_createSubProduct", LOG_DEBUG);
$resql=$this->db->query($sql);
|