forked from Wavyzz/dolibarr
Merge branch 'dinamic-prices-product' of
https://github.com/IonAgorria/dolibarr into IonAgorria-dinamic-prices-product Conflicts: htdocs/install/mysql/migration/3.7.0-3.8.0.sql htdocs/product/fournisseurs.php
This commit is contained in:
24
htdocs/core/boxes/box_produits.php
Normal file → Executable file
24
htdocs/core/boxes/box_produits.php
Normal file → Executable file
@@ -63,7 +63,7 @@ class box_produits extends ModeleBoxes
|
||||
|
||||
if ($user->rights->produit->lire || $user->rights->service->lire)
|
||||
{
|
||||
$sql = "SELECT p.rowid, p.label, p.price, p.price_base_type, p.price_ttc, p.fk_product_type, p.tms, p.tosell, p.tobuy";
|
||||
$sql = "SELECT p.rowid, p.label, p.price, p.price_base_type, p.price_ttc, p.fk_product_type, p.tms, p.tosell, p.tobuy, p.fk_price_expression";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
|
||||
$sql.= ' WHERE p.entity IN ('.getEntity($productstatic->element, 1).')';
|
||||
if (empty($user->rights->produit->lire)) $sql.=' AND p.fk_product_type != 0';
|
||||
@@ -106,7 +106,7 @@ class box_produits extends ModeleBoxes
|
||||
$this->info_box_contents[$i][1] = array('td' => 'align="left"',
|
||||
'text' => $objp->label,
|
||||
'url' => DOL_URL_ROOT."/product/card.php?id=".$objp->rowid);
|
||||
|
||||
if (empty($objp->fk_price_expression)) {
|
||||
if ($objp->price_base_type == 'HT')
|
||||
{
|
||||
$price=price($objp->price);
|
||||
@@ -117,6 +117,26 @@ class box_produits extends ModeleBoxes
|
||||
$price=price($objp->price_ttc);
|
||||
$price_base_type=$langs->trans("TTC");
|
||||
}
|
||||
}
|
||||
else //Parse the dinamic price
|
||||
{
|
||||
$product = new Product($this->db);
|
||||
$product->fetch($objp->rowid, '', '', 1);
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProduct($product);
|
||||
if ($price_result >= 0) {
|
||||
if ($objp->price_base_type == 'HT')
|
||||
{
|
||||
$price_base_type=$langs->trans("HT");
|
||||
}
|
||||
else
|
||||
{
|
||||
$price_result = $price_result * (1 + ($product->tva_tx / 100));
|
||||
$price_base_type=$langs->trans("TTC");
|
||||
}
|
||||
$price=price($price_result);
|
||||
}
|
||||
}
|
||||
$this->info_box_contents[$i][2] = array('td' => 'align="right"',
|
||||
'text' => $price);
|
||||
|
||||
|
||||
21
htdocs/core/boxes/box_produits_alerte_stock.php
Normal file → Executable file
21
htdocs/core/boxes/box_produits_alerte_stock.php
Normal file → Executable file
@@ -114,6 +114,7 @@ class box_produits_alerte_stock extends ModeleBoxes
|
||||
'text' => $objp->label,
|
||||
'url' => DOL_URL_ROOT."/product/card.php?id=".$objp->rowid);
|
||||
|
||||
if (empty($objp->fk_price_expression)) {
|
||||
if ($objp->price_base_type == 'HT')
|
||||
{
|
||||
$price=price($objp->price);
|
||||
@@ -124,6 +125,26 @@ class box_produits_alerte_stock extends ModeleBoxes
|
||||
$price=price($objp->price_ttc);
|
||||
$price_base_type=$langs->trans("TTC");
|
||||
}
|
||||
}
|
||||
else //Parse the dinamic price
|
||||
{
|
||||
$product = new Product($this->db);
|
||||
$product->fetch($objp->rowid, '', '', 1);
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProduct($product);
|
||||
if ($price_result >= 0) {
|
||||
if ($objp->price_base_type == 'HT')
|
||||
{
|
||||
$price_base_type=$langs->trans("HT");
|
||||
}
|
||||
else
|
||||
{
|
||||
$price_result = $price_result * (1 + ($product->tva_tx / 100));
|
||||
$price_base_type=$langs->trans("TTC");
|
||||
}
|
||||
$price=price($price_result);
|
||||
}
|
||||
}
|
||||
$this->info_box_contents[$i][2] = array('td' => 'align="right"',
|
||||
'text' => $price);
|
||||
|
||||
|
||||
@@ -1466,7 +1466,7 @@ class Form
|
||||
$outarray=array();
|
||||
|
||||
$sql = "SELECT ";
|
||||
$sql.= " p.rowid, p.label, p.ref, p.description, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.duration, p.stock";
|
||||
$sql.= " p.rowid, p.label, p.ref, p.description, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.duration, p.stock, p.fk_price_expression";
|
||||
|
||||
//Price by customer
|
||||
if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
|
||||
@@ -1545,6 +1545,8 @@ class Form
|
||||
$result=$this->db->query($sql);
|
||||
if ($result)
|
||||
{
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/priceparser.class.php';
|
||||
$num = $this->db->num_rows($result);
|
||||
|
||||
$out.='<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
|
||||
@@ -1594,6 +1596,19 @@ class Form
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!empty($objp->fk_price_expression)) {
|
||||
$price_product = new Product($this->db);
|
||||
$price_product->fetch($objp->rowid, '', '', 1);
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProduct($price_product);
|
||||
if ($price_result >= 0) {
|
||||
$objp->price = $price_result;
|
||||
$objp->unitprice = $price_result;
|
||||
//Calculate the VAT
|
||||
$objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
|
||||
$objp->price_ttc = price2num($objp->price_ttc,'MU');
|
||||
}
|
||||
}
|
||||
$this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected);
|
||||
// Add new entry
|
||||
// "key" value of json key array is used by jQuery automatically as selected value
|
||||
@@ -1875,7 +1890,7 @@ class Form
|
||||
|
||||
$sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration,";
|
||||
$sql.= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
|
||||
$sql.= " pfp.fk_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
|
||||
$sql.= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
|
||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
|
||||
if ($socid) $sql.= " AND pfp.fk_soc = ".$socid;
|
||||
@@ -1957,9 +1972,9 @@ class Form
|
||||
{
|
||||
$outqty=$objp->quantity;
|
||||
$outdiscount=$objp->remise_percent;
|
||||
if (!empty($objp->fk_price_expression)) {
|
||||
if (!empty($objp->fk_supplier_price_expression)) {
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProductSupplier($objp->fk_product, $objp->fk_price_expression, $objp->quantity, $objp->tva_tx);
|
||||
$price_result = $priceparser->parseProductSupplier($objp->fk_product, $objp->fk_supplier_price_expression, $objp->quantity, $objp->tva_tx);
|
||||
if ($price_result >= 0) {
|
||||
$objp->fprice = $price_result;
|
||||
if ($objp->quantity >= 1)
|
||||
@@ -2056,7 +2071,7 @@ class Form
|
||||
|
||||
$sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration,";
|
||||
$sql.= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.unitprice,";
|
||||
$sql.= " pfp.fk_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
|
||||
$sql.= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
|
||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
|
||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
|
||||
@@ -2096,9 +2111,9 @@ class Form
|
||||
}
|
||||
$opt.= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
|
||||
|
||||
if (!empty($objp->fk_price_expression)) {
|
||||
if (!empty($objp->fk_supplier_price_expression)) {
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProductSupplier($objp->fk_product, $objp->fk_price_expression, $objp->quantity, $objp->tva_tx);
|
||||
$price_result = $priceparser->parseProductSupplier($objp->fk_product, $objp->fk_supplier_price_expression, $objp->quantity, $objp->tva_tx);
|
||||
if ($price_result >= 0) {
|
||||
$objp->fprice = $price_result;
|
||||
if ($objp->quantity >= 1)
|
||||
|
||||
@@ -52,7 +52,7 @@ if ($idprod > 0)
|
||||
$sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration,";
|
||||
$sql.= " pfp.ref_fourn,";
|
||||
$sql.= " pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice, pfp.charges, pfp.unitcharges,";
|
||||
$sql.= " pfp.fk_price_expression, pfp.tva_tx, s.nom as name";
|
||||
$sql.= " pfp.fk_supplier_price_expression, pfp.tva_tx, s.nom as name";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp";
|
||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = pfp.fk_product";
|
||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = pfp.fk_soc";
|
||||
@@ -76,9 +76,9 @@ if ($idprod > 0)
|
||||
{
|
||||
$objp = $db->fetch_object($result);
|
||||
|
||||
if (!empty($objp->fk_price_expression)) {
|
||||
if (!empty($objp->fk_supplier_price_expression)) {
|
||||
$priceparser = new PriceParser($db);
|
||||
$price_result = $priceparser->parseProductSupplier($idprod, $objp->fk_price_expression, $objp->quantity, $objp->tva_tx);
|
||||
$price_result = $priceparser->parseProductSupplier($idprod, $objp->fk_supplier_price_expression, $objp->quantity, $objp->tva_tx);
|
||||
if ($price_result >= 0) {
|
||||
$objp->fprice = $price_result;
|
||||
if ($objp->quantity >= 1)
|
||||
|
||||
@@ -56,7 +56,7 @@ class ProductFournisseur extends Product
|
||||
var $fourn_unitprice;
|
||||
var $fourn_tva_npr;
|
||||
|
||||
var $fk_price_expression;
|
||||
var $fk_supplier_price_expression;
|
||||
|
||||
|
||||
/**
|
||||
@@ -330,7 +330,7 @@ class ProductFournisseur extends Product
|
||||
function fetch_product_fournisseur_price($rowid, $ignore_expression = 0)
|
||||
{
|
||||
$sql = "SELECT pfp.rowid, pfp.price, pfp.quantity, pfp.unitprice, pfp.remise_percent, pfp.remise, pfp.tva_tx, pfp.fk_availability,";
|
||||
$sql.= " pfp.fk_soc, pfp.ref_fourn, pfp.fk_product, pfp.charges, pfp.unitcharges, pfp.fk_price_expression"; // , pfp.recuperableonly as fourn_tva_npr"; FIXME this field not exist in llx_product_fournisseur_price
|
||||
$sql.= " pfp.fk_soc, pfp.ref_fourn, pfp.fk_product, pfp.charges, pfp.unitcharges, pfp.fk_supplier_price_expression"; // , pfp.recuperableonly as fourn_tva_npr"; FIXME this field not exist in llx_product_fournisseur_price
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp";
|
||||
$sql.= " WHERE pfp.rowid = ".$rowid;
|
||||
|
||||
@@ -350,16 +350,16 @@ class ProductFournisseur extends Product
|
||||
$this->fourn_remise = $obj->remise;
|
||||
$this->fourn_unitprice = $obj->unitprice;
|
||||
$this->fourn_unitcharges = $obj->unitcharges;
|
||||
$this->tva_tx = $obj->tva_tx;
|
||||
$this->fourn_tva_tx = $obj->tva_tx;
|
||||
$this->product_id = $obj->fk_product; // deprecated
|
||||
$this->fk_product = $obj->fk_product;
|
||||
$this->fk_availability = $obj->fk_availability;
|
||||
//$this->fourn_tva_npr = $obj->fourn_tva_npr; // FIXME this field not exist in llx_product_fournisseur_price
|
||||
$this->fk_price_expression = $obj->fk_price_expression;
|
||||
$this->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
|
||||
|
||||
if (empty($ignore_expression) && !empty($this->fk_price_expression)) {
|
||||
if (empty($ignore_expression) && !empty($this->fk_supplier_price_expression)) {
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProductSupplier($this->fk_product, $this->fk_price_expression, $this->fourn_qty, $this->fourn_tva_tx);
|
||||
$price_result = $priceparser->parseProductSupplier($this->fk_product, $this->fk_supplier_price_expression, $this->fourn_qty, $this->fourn_tva_tx);
|
||||
if ($price_result >= 0) {
|
||||
$this->fourn_price = $price_result;
|
||||
//recalculation of unitprice, as probably the price changed...
|
||||
@@ -402,7 +402,7 @@ class ProductFournisseur extends Product
|
||||
global $conf;
|
||||
|
||||
$sql = "SELECT s.nom as supplier_name, s.rowid as fourn_id,";
|
||||
$sql.= " pfp.rowid as product_fourn_pri_id, pfp.ref_fourn, pfp.fk_product as product_fourn_id, pfp.fk_price_expression,";
|
||||
$sql.= " pfp.rowid as product_fourn_pri_id, pfp.ref_fourn, pfp.fk_product as product_fourn_id, pfp.fk_supplier_price_expression,";
|
||||
$sql.= " pfp.price, pfp.quantity, pfp.unitprice, pfp.remise_percent, pfp.remise, pfp.tva_tx, pfp.fk_availability, pfp.charges, pfp.unitcharges, pfp.info_bits";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp";
|
||||
$sql.= ", ".MAIN_DB_PREFIX."societe as s";
|
||||
@@ -439,11 +439,11 @@ class ProductFournisseur extends Product
|
||||
$prodfourn->fk_availability = $record["fk_availability"];
|
||||
$prodfourn->id = $prodid;
|
||||
$prodfourn->fourn_tva_npr = $record["info_bits"];
|
||||
$prodfourn->fk_price_expression = $record["fk_price_expression"];
|
||||
$prodfourn->fk_supplier_price_expression = $record["fk_supplier_price_expression"];
|
||||
|
||||
if (!empty($prodfourn->fk_price_expression)) {
|
||||
if (!empty($prodfourn->fk_supplier_price_expression)) {
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProductSupplier($prodid, $prodfourn->fk_price_expression, $prodfourn->fourn_qty, $prodfourn->fourn_tva_tx);
|
||||
$price_result = $priceparser->parseProductSupplier($prodid, $prodfourn->fk_supplier_price_expression, $prodfourn->fourn_qty, $prodfourn->fourn_tva_tx);
|
||||
if ($price_result >= 0) {
|
||||
$prodfourn->fourn_price = $price_result;
|
||||
$prodfourn->fourn_unitprice = null; //force recalculation of unitprice, as probably the price changed...
|
||||
@@ -501,35 +501,74 @@ class ProductFournisseur extends Product
|
||||
$sql = "SELECT s.nom as supplier_name, s.rowid as fourn_id,";
|
||||
$sql.= " pfp.rowid as product_fourn_price_id, pfp.ref_fourn,";
|
||||
$sql.= " pfp.price, pfp.quantity, pfp.unitprice, pfp.tva_tx, pfp.charges, pfp.unitcharges, ";
|
||||
$sql.= " pfp.remise, pfp.remise_percent, pfp.fk_price_expression";
|
||||
$sql.= " pfp.remise, pfp.remise_percent, pfp.fk_supplier_price_expression";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."product_fournisseur_price as pfp";
|
||||
$sql.= " WHERE s.entity IN (".getEntity('societe', 1).")";
|
||||
$sql.= " AND pfp.fk_product = ".$prodid;
|
||||
$sql.= " AND pfp.fk_soc = s.rowid";
|
||||
if ($qty > 0) $sql.= " AND pfp.quantity <= ".$qty;
|
||||
$sql.= " ORDER BY pfp.unitprice";
|
||||
$sql.= $this->db->plimit(1);
|
||||
|
||||
dol_syslog(get_class($this)."::find_min_price_product_fournisseur", LOG_DEBUG);
|
||||
|
||||
$resql = $this->db->query($sql);
|
||||
if ($resql)
|
||||
{
|
||||
$record = $this->db->fetch_array($resql);
|
||||
$record_array = array();
|
||||
|
||||
//Store each record to array for later search of min
|
||||
while ($record = $this->db->fetch_array($resql))
|
||||
{
|
||||
$record_array[]=$record;
|
||||
}
|
||||
|
||||
if (count($record_array) == 0)
|
||||
{
|
||||
$this->db->free($resql);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$min = -1;
|
||||
foreach($record_array as $record)
|
||||
{
|
||||
$fourn_price = $record["price"];
|
||||
$fourn_unitprice = $record["unitprice"];
|
||||
if (!empty($record["fk_supplier_price_expression"])) {
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProductSupplier($prodid, $record["fk_supplier_price_expression"], $record["quantity"], $record["tva_tx"]);
|
||||
if ($price_result >= 0) {
|
||||
$fourn_price = price2num($price_result,'MU');
|
||||
if ($record["quantity"] != 0)
|
||||
{
|
||||
$fourn_unitprice = price2num($fourn_price/$record["quantity"],'MU');
|
||||
}
|
||||
else
|
||||
{
|
||||
$fourn_unitprice = $fourn_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($fourn_unitprice < $min || $min == -1)
|
||||
{
|
||||
$this->product_fourn_price_id = $record["product_fourn_price_id"];
|
||||
$this->fourn_ref = $record["ref_fourn"];
|
||||
$this->fourn_price = $record["price"];
|
||||
$this->fourn_price = $fourn_price;
|
||||
$this->fourn_qty = $record["quantity"];
|
||||
$this->fourn_remise_percent = $record["remise_percent"];
|
||||
$this->fourn_remise = $record["remise"];
|
||||
$this->fourn_unitprice = $record["unitprice"];
|
||||
$this->fourn_unitprice = $fourn_unitprice;
|
||||
$this->fourn_charges = $record["charges"];
|
||||
$this->fourn_unitcharges = $record["unitcharges"];
|
||||
$this->fourn_tva_tx = $record["tva_tx"];
|
||||
$this->fourn_id = $record["fourn_id"];
|
||||
$this->fourn_name = $record["supplier_name"];
|
||||
$this->fk_price_expression = $record["fk_price_expression"];
|
||||
$this->fk_supplier_price_expression = $record["fk_supplier_price_expression"];
|
||||
$this->id = $prodid;
|
||||
$min = $this->fourn_unitprice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->free($resql);
|
||||
return 1;
|
||||
}
|
||||
@@ -541,23 +580,24 @@ class ProductFournisseur extends Product
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the price expression
|
||||
* Sets the supplier price expression
|
||||
*
|
||||
* @param string $expression_id Expression
|
||||
* @param int $expression_id Expression
|
||||
* @return int <0 if KO, >0 if OK
|
||||
*/
|
||||
function setPriceExpression($expression_id)
|
||||
function setSupplierPriceExpression($expression_id)
|
||||
{
|
||||
global $conf;
|
||||
|
||||
// Clean parameters
|
||||
$this->db->begin();
|
||||
$expression_id = $expression_id != 0 ? $expression_id : 'NULL';
|
||||
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
|
||||
$sql.= " SET fk_price_expression = ".$expression_id;
|
||||
$sql.= " SET fk_supplier_price_expression = ".$expression_id;
|
||||
$sql.= " WHERE rowid = ".$this->product_fourn_price_id;
|
||||
|
||||
dol_syslog(get_class($this)."::setPriceExpression", LOG_DEBUG);
|
||||
dol_syslog(get_class($this)."::setSupplierPriceExpression", LOG_DEBUG);
|
||||
|
||||
$resql = $this->db->query($sql);
|
||||
if ($resql)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
-- -- VPGSQL8.2 DELETE FROM llx_usergroup_user WHERE fk_user NOT IN (SELECT rowid from llx_user);
|
||||
-- -- VMYSQL4.1 DELETE FROM llx_usergroup_user WHERE fk_usergroup NOT IN (SELECT rowid from llx_usergroup);
|
||||
|
||||
|
||||
--create table for price expressions and add column in product supplier
|
||||
create table llx_c_price_expression
|
||||
(
|
||||
@@ -26,6 +27,11 @@ create table llx_c_price_expression
|
||||
expression varchar(80) NOT NULL
|
||||
)ENGINE=innodb;
|
||||
|
||||
ALTER TABLE llx_product_fournisseur_price ADD COLUMN fk_supplier_price_expression integer DEFAULT NULL;
|
||||
ALTER TABLE llx_product ADD COLUMN fk_price_expression integer DEFAULT NULL;
|
||||
ALTER TABLE llx_product_price ADD COLUMN fk_price_expression integer DEFAULT NULL;
|
||||
|
||||
|
||||
--create table for user conf of printing driver
|
||||
CREATE TABLE llx_printing
|
||||
(
|
||||
|
||||
1
htdocs/install/mysql/tables/llx_product.sql
Normal file → Executable file
1
htdocs/install/mysql/tables/llx_product.sql
Normal file → Executable file
@@ -76,5 +76,6 @@ create table llx_product
|
||||
finished tinyint DEFAULT NULL,
|
||||
hidden tinyint DEFAULT 0, -- Not used. Deprecated.
|
||||
import_key varchar(14), -- Import key
|
||||
fk_price_expression integer, -- Link to the rule for dynamic price calculation
|
||||
desiredstock integer DEFAULT 0
|
||||
)ENGINE=innodb;
|
||||
|
||||
@@ -39,6 +39,6 @@ create table llx_product_fournisseur_price
|
||||
tva_tx double(6,3) NOT NULL,
|
||||
info_bits integer NOT NULL DEFAULT 0,
|
||||
fk_user integer,
|
||||
fk_price_expression integer, -- Link to the rule for dynamic amount calculation
|
||||
fk_supplier_price_expression integer, -- Link to the rule for dynamic price calculation
|
||||
import_key varchar(14) -- Import key
|
||||
)ENGINE=innodb;
|
||||
|
||||
1
htdocs/install/mysql/tables/llx_product_price.sql
Normal file → Executable file
1
htdocs/install/mysql/tables/llx_product_price.sql
Normal file → Executable file
@@ -38,6 +38,7 @@ create table llx_product_price
|
||||
fk_user_author integer,
|
||||
tosell tinyint DEFAULT 1,
|
||||
price_by_qty integer NOT NULL DEFAULT 0,
|
||||
fk_price_expression integer, -- Link to the rule for dynamic price calculation
|
||||
import_key varchar(14)
|
||||
)ENGINE=innodb;
|
||||
|
||||
|
||||
@@ -244,6 +244,9 @@ MinimumPriceLimit=Minimum price can't be lower that %s
|
||||
MinimumRecommendedPrice=Minimum recommended price is : %s
|
||||
PriceExpressionEditor=Price expression editor
|
||||
PriceExpressionSelected=Selected price expression
|
||||
PriceExpressionEditorHelp="price = 2 + 2" or "2 + 2" for setting the price<br>ExtraFields are variables like "#options_myextrafieldkey# * 2"<br>There are special variables like #quantity# and #tva_tx#<br>Use ; to separate expressions
|
||||
PriceExpressionEditorHelp1="price = 2 + 2" or "2 + 2" for setting the price. Use ; to separate expressions
|
||||
PriceExpressionEditorHelp2=You can access ExtraFields with variables like <b>#options_myextrafieldkey#</b>
|
||||
PriceExpressionEditorHelp3=In both product/service and supplier prices there are these variables available:<br><b>#tva_tx# #localtax1_tx# #localtax2_tx# #weight# #length# #surface# #price_min#</b>
|
||||
PriceExpressionEditorHelp4=In product/service price only: <b>#supplier_min_price#</b><br>In supplier prices only: <b>#supplier_quantity# and #supplier_tva_tx#</b>
|
||||
PriceMode=Price mode
|
||||
PriceNumeric=Number
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
require_once DOL_DOCUMENT_ROOT.'/includes/evalmath/evalmath.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/priceexpression.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
|
||||
|
||||
@@ -121,12 +122,33 @@ class PriceParser
|
||||
/**
|
||||
* Calculates price based on expression
|
||||
*
|
||||
* @param array $values Strings to replaces
|
||||
* @param Product $product The Product object to get information
|
||||
* @param String $expression The expression to parse
|
||||
* @param array $values Strings to replaces
|
||||
* @return int > 0 if OK, < 1 if KO
|
||||
*/
|
||||
public function parseExpression($values, $expression)
|
||||
public function parseExpression($product, $expression, $values)
|
||||
{
|
||||
//Accessible product values by expressions
|
||||
$values = array_merge($values, array(
|
||||
"tva_tx" => $product->tva_tx,
|
||||
"localtax1_tx" => $product->localtax1_tx,
|
||||
"localtax2_tx" => $product->localtax2_tx,
|
||||
"weight" => $product->weight,
|
||||
"length" => $product->length,
|
||||
"surface" => $product->surface,
|
||||
"price_min" => $product->price_min,
|
||||
));
|
||||
|
||||
//Retreive all extrafield for product and add it to values
|
||||
$extrafields = new ExtraFields($this->db);
|
||||
$extralabels = $extrafields->fetch_name_optionals_label('product', true);
|
||||
$product->fetch_optionals($product->id, $extralabels);
|
||||
foreach ($extrafields->attribute_label as $key=>$label)
|
||||
{
|
||||
$values['options_'.$key] = $product->array_options['options_'.$key];
|
||||
}
|
||||
|
||||
//Check if empty
|
||||
$expression = trim($expression);
|
||||
if (empty($expression))
|
||||
@@ -182,37 +204,79 @@ class PriceParser
|
||||
return $vars["price"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates product price based on product id and string expression
|
||||
*
|
||||
* @param Product $product The Product object to get information
|
||||
* @param string $expression The expression to parse
|
||||
* @param array $extra_values Any aditional values for expression
|
||||
* @return int > 0 if OK, < 1 if KO
|
||||
*/
|
||||
public function parseProductExpression($product, $expression, $extra_values = array())
|
||||
{
|
||||
//Get the supplier min
|
||||
$productFournisseur = new ProductFournisseur($this->db);
|
||||
$supplier_min_price = $productFournisseur->find_min_price_product_fournisseur($product->id);
|
||||
|
||||
//Accessible values by expressions
|
||||
$extra_values = array_merge($extra_values, array(
|
||||
"supplier_min_price" => $supplier_min_price,
|
||||
));
|
||||
|
||||
//Parse the expression and return the price, if not error occurred check if price is higher than min
|
||||
$result = $this->parseExpression($product, $expression, $extra_values);
|
||||
if (empty($this->error)) {
|
||||
if ($result < $product->price_min) {
|
||||
$result = $product->price_min;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates product price based on product id and expression id
|
||||
*
|
||||
* @param Product $product The Product object to get information
|
||||
* @param int $expression_id The expression to parse
|
||||
* @param array $extra_values Any aditional values for expression
|
||||
* @return int > 0 if OK, < 1 if KO
|
||||
*/
|
||||
public function parseProduct($product, $extra_values = array())
|
||||
{
|
||||
//Get the expression from db
|
||||
$price_expression = new PriceExpression($this->db);
|
||||
$res = $price_expression->fetch($product->fk_price_expression);
|
||||
if ($res < 1) {
|
||||
$this->error = array(19, null);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Parse the expression and return the price
|
||||
return $this->parseProductExpression($product, $price_expression->expression, $extra_values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates supplier product price based on product id and string expression
|
||||
*
|
||||
* @param int $product_id The Product id to get information
|
||||
* @param string $expression The expression to parse
|
||||
* @param int $quantity Min quantity
|
||||
* @param int $tva_tx VAT rate
|
||||
* @param int $quantity Supplier Min quantity
|
||||
* @param int $tva_tx Supplier VAT rate
|
||||
* @param array $extra_values Any aditional values for expression
|
||||
* @return int > 0 if OK, < 1 if KO
|
||||
*/
|
||||
public function parseProductSupplierExpression($product_id, $expression, $quantity = null, $tva_tx = null, $extra_values = array())
|
||||
{
|
||||
//Accessible values by expressions
|
||||
$expression_values = array(
|
||||
"quantity" => $quantity,
|
||||
"tva_tx" => $tva_tx,
|
||||
);
|
||||
$expression_values = array_merge($expression_values, $extra_values);
|
||||
|
||||
//Retreive all extrafield for product and add it to expression_values
|
||||
$extrafields = new ExtraFields($this->db);
|
||||
$extralabels = $extrafields->fetch_name_optionals_label('product', true);
|
||||
//Get the product data
|
||||
$product = new Product($this->db);
|
||||
$product->fetch_optionals($product_id, $extralabels);
|
||||
foreach($extrafields->attribute_label as $key=>$label)
|
||||
{
|
||||
$expression_values['options_'.$key] = $product->array_options['options_'.$key];
|
||||
}
|
||||
$product->fetch($product_id, '', '', 1);
|
||||
|
||||
//Parse the expression and return the price
|
||||
return $this->parseExpression($expression_values, $expression);
|
||||
//Accessible values by expressions
|
||||
$extra_values = array_merge($extra_values, array(
|
||||
"supplier_quantity" => $quantity,
|
||||
"supplier_tva_tx" => $tva_tx,
|
||||
));
|
||||
return $this->parseExpression($product, $expression, $extra_values);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,9 +291,10 @@ class PriceParser
|
||||
*/
|
||||
public function parseProductSupplier($product_id, $expression_id, $quantity = null, $tva_tx = null, $extra_values = array())
|
||||
{
|
||||
//Get the expression from db
|
||||
$price_expression = new PriceExpression($this->db);
|
||||
$res = $price_expression->fetch($expression_id);
|
||||
if ($res > 1) {
|
||||
if ($res < 1) {
|
||||
$this->error = array(19, null);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* Copyright (C) 2011-2014 Alexandre Spangaro <alexandre.spangaro@gmail.com>
|
||||
* Copyright (C) 2014 Henry Florian <florian.henry@open-concept.pro>
|
||||
* Copyright (C) 2014 Philippe Grand <philippe.grand@atoo-net.com>
|
||||
* Copyright (C) 2014 Ion agorria <ion@agorria.com>
|
||||
*
|
||||
* 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
|
||||
@@ -30,8 +31,9 @@
|
||||
* \ingroup produit
|
||||
* \brief File of class to manage predefined products or services
|
||||
*/
|
||||
require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/priceparser.class.php';
|
||||
|
||||
|
||||
/**
|
||||
@@ -166,6 +168,8 @@ class Product extends CommonObject
|
||||
//note not visible on orders and invoices
|
||||
var $note;
|
||||
|
||||
var $fk_price_expression;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -1112,9 +1116,9 @@ class Product extends CommonObject
|
||||
|
||||
// Add new price
|
||||
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price(price_level,date_price,fk_product,fk_user_author,price,price_ttc,price_base_type,tosell,tva_tx,recuperableonly,";
|
||||
$sql.= " localtax1_tx, localtax2_tx, price_min,price_min_ttc,price_by_qty,entity) ";
|
||||
$sql.= " localtax1_tx, localtax2_tx, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
|
||||
$sql.= " VALUES(".($level?$level:1).", '".$this->db->idate($now)."',".$this->id.",".$user->id.",".$this->price.",".$this->price_ttc.",'".$this->price_base_type."',".$this->status.",".$this->tva_tx.",".$this->tva_npr.",";
|
||||
$sql.= " ".$this->localtax1_tx.",".$this->localtax2_tx.",".$this->price_min.",".$this->price_min_ttc.",".$this->price_by_qty.",".$conf->entity;
|
||||
$sql.= " ".$this->localtax1_tx.",".$this->localtax2_tx.",".$this->price_min.",".$this->price_min_ttc.",".$this->price_by_qty.",".$conf->entity.",".$this->fk_price_expression;
|
||||
$sql.= ")";
|
||||
|
||||
dol_syslog(get_class($this)."_log_price", LOG_DEBUG);
|
||||
@@ -1176,7 +1180,7 @@ class Product extends CommonObject
|
||||
|
||||
// We do select by searching with qty and prodfournprice
|
||||
$sql = "SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity,";
|
||||
$sql.= " pfp.fk_product, pfp.ref_fourn, pfp.fk_soc, pfp.tva_tx, pfp.fk_price_expression";
|
||||
$sql.= " pfp.fk_product, pfp.ref_fourn, pfp.fk_soc, pfp.tva_tx, pfp.fk_supplier_price_expression";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp";
|
||||
$sql.= " WHERE pfp.rowid = ".$prodfournprice;
|
||||
if ($qty) $sql.= " AND pfp.quantity <= ".$qty;
|
||||
@@ -1188,9 +1192,9 @@ class Product extends CommonObject
|
||||
$obj = $this->db->fetch_object($resql);
|
||||
if ($obj && $obj->quantity > 0) // If found
|
||||
{
|
||||
if (!empty($obj->fk_price_expression)) {
|
||||
if (!empty($obj->fk_supplier_price_expression)) {
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProductSupplier($obj->fk_product, $obj->fk_price_expression, $obj->quantity, $obj->tva_tx);
|
||||
$price_result = $priceparser->parseProductSupplier($obj->fk_product, $obj->fk_supplier_price_expression, $obj->quantity, $obj->tva_tx);
|
||||
if ($price_result >= 0) {
|
||||
$obj->price = $price_result;
|
||||
}
|
||||
@@ -1206,7 +1210,7 @@ class Product extends CommonObject
|
||||
{
|
||||
// We do same select again but searching with qty, ref and id product
|
||||
$sql = "SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.fk_soc,";
|
||||
$sql.= " pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.tva_tx, pfp.fk_price_expression";
|
||||
$sql.= " pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.tva_tx, pfp.fk_supplier_price_expression";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp";
|
||||
$sql.= " WHERE pfp.ref_fourn = '".$fourn_ref."'";
|
||||
$sql.= " AND pfp.fk_product = ".$product_id;
|
||||
@@ -1221,9 +1225,9 @@ class Product extends CommonObject
|
||||
$obj = $this->db->fetch_object($resql);
|
||||
if ($obj && $obj->quantity > 0) // If found
|
||||
{
|
||||
if (!empty($obj->fk_price_expression)) {
|
||||
if (!empty($obj->fk_supplier_price_expression)) {
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProductSupplier($obj->fk_product, $obj->fk_price_expression, $obj->quantity, $obj->tva_tx);
|
||||
$price_result = $priceparser->parseProductSupplier($obj->fk_product, $obj->fk_supplier_price_expression, $obj->quantity, $obj->tva_tx);
|
||||
if ($result >= 0) {
|
||||
$obj->price = $price_result;
|
||||
}
|
||||
@@ -1397,6 +1401,39 @@ class Product extends CommonObject
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the supplier price expression
|
||||
*
|
||||
* @param int $expression_id Expression
|
||||
* @return int <0 if KO, >0 if OK
|
||||
*/
|
||||
function setPriceExpression($expression_id)
|
||||
{
|
||||
global $conf;
|
||||
|
||||
// Clean parameters
|
||||
$this->db->begin();
|
||||
$expression_id = $expression_id != 0 ? $expression_id : 'NULL';
|
||||
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."product";
|
||||
$sql.= " SET fk_price_expression = ".$expression_id;
|
||||
$sql.= " WHERE rowid = ".$this->id;
|
||||
|
||||
dol_syslog(get_class($this)."::setPriceExpression", LOG_DEBUG);
|
||||
|
||||
$resql = $this->db->query($sql);
|
||||
if ($resql)
|
||||
{
|
||||
$this->db->commit();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->error=$this->db->error()." sql=".$sql;
|
||||
$this->db->rollback();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a product in memory from database
|
||||
@@ -1404,9 +1441,10 @@ class Product extends CommonObject
|
||||
* @param int $id Id of product/service to load
|
||||
* @param string $ref Ref of product/service to load
|
||||
* @param string $ref_ext Ref ext of product/service to load
|
||||
* @param int $ignore_expression Ignores the math expression for calculating price and uses the db value instead
|
||||
* @return int <0 if KO, 0 if not found, >0 if OK
|
||||
*/
|
||||
function fetch($id='',$ref='',$ref_ext='')
|
||||
function fetch($id='', $ref='', $ref_ext='', $ignore_expression = 0)
|
||||
{
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
|
||||
|
||||
@@ -1428,7 +1466,7 @@ class Product extends CommonObject
|
||||
$sql.= " weight, weight_units, length, length_units, surface, surface_units, volume, volume_units, barcode, fk_barcode_type, finished,";
|
||||
$sql.= " accountancy_code_buy, accountancy_code_sell, stock, pmp,";
|
||||
$sql.= " datec, tms, import_key, entity, desiredstock, tobatch";
|
||||
$sql.= " ,ref_ext";
|
||||
$sql.= " ,ref_ext, fk_price_expression";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product";
|
||||
if ($id) $sql.= " WHERE rowid = ".$this->db->escape($id);
|
||||
else
|
||||
@@ -1505,6 +1543,7 @@ class Product extends CommonObject
|
||||
$this->entity = $obj->entity;
|
||||
|
||||
$this->ref_ext = $obj->ref_ext;
|
||||
$this->fk_price_expression = $obj->fk_price_expression;
|
||||
|
||||
$this->db->free($resql);
|
||||
|
||||
@@ -1640,6 +1679,19 @@ class Product extends CommonObject
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->fk_price_expression) && empty($ignore_expression))
|
||||
{
|
||||
$priceparser = new PriceParser($this->db);
|
||||
$price_result = $priceparser->parseProduct($this);
|
||||
if ($price_result >= 0)
|
||||
{
|
||||
$this->price = $price_result;
|
||||
//Calculate the VAT
|
||||
$this->price_ttc = price2num($this->price) * (1 + ($this->tva_tx / 100));
|
||||
$this->price_ttc = price2num($this->price_ttc,'MU');
|
||||
}
|
||||
}
|
||||
|
||||
// We should not load stock at each fetch. If someone need stock, he must call load_stock after fetch.
|
||||
//$res=$this->load_stock();
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ $title = GETPOST('expression_title', 'alpha');
|
||||
$expression = GETPOST('expression');
|
||||
$tab = GETPOST('tab', 'alpha');
|
||||
$tab = (!empty($tab)) ? $tab : 'card';
|
||||
$tab = strtolower($tab);
|
||||
|
||||
// Security check
|
||||
$result=restrictedArea($user,'produit|service&fournisseur',$id,'product&product','','','rowid');
|
||||
@@ -82,6 +83,7 @@ if ($action == 'add')
|
||||
if ($result > 0) //created successfully, set the eid to newly created entry
|
||||
{
|
||||
$eid = $price_expression->id;
|
||||
setEventMessage($langs->trans("RecordSaved"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -123,6 +125,10 @@ if ($action == 'update')
|
||||
{
|
||||
setEventMessage("update: ".$price_expression->error, 'errors');
|
||||
}
|
||||
else
|
||||
{
|
||||
setEventMessage($langs->trans("RecordSaved"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($result < 0)
|
||||
@@ -179,7 +185,8 @@ print '<input class="flat" name="expression_title" size="15" value="'.($price_ex
|
||||
print '</td></tr>';
|
||||
|
||||
//Price expression editor
|
||||
print '<tr><td class="fieldrequired">'.$form->textwithpicto($langs->trans("PriceExpressionEditor"),$langs->trans("PriceExpressionEditorHelp"),1).'</td><td>';
|
||||
$help_text = $langs->trans("PriceExpressionEditorHelp1").'<br><br>'.$langs->trans("PriceExpressionEditorHelp2").'<br><br>'.$langs->trans("PriceExpressionEditorHelp3").'<br><br>'.$langs->trans("PriceExpressionEditorHelp4");
|
||||
print '<tr><td class="fieldrequired">'.$form->textwithpicto($langs->trans("PriceExpressionEditor"),$help_text,1).'</td><td>';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
|
||||
$doleditor=new DolEditor('expression',isset($price_expression->expression)?$price_expression->expression:'','',300,'','',false,false,false,4,80);
|
||||
$doleditor->Create();
|
||||
@@ -202,7 +209,7 @@ print '</center>';
|
||||
|
||||
print '</form>';
|
||||
|
||||
// This code reloads the page depending of selected option, goes back in history when back is pressed
|
||||
// This code reloads the page depending of selected option, goes to page selected by tab when back is pressed
|
||||
print '<script type="text/javascript">
|
||||
jQuery(document).ready(run);
|
||||
function run() {
|
||||
@@ -210,7 +217,7 @@ print '<script type="text/javascript">
|
||||
jQuery("#expression_selection").change(on_change);
|
||||
}
|
||||
function on_click() {
|
||||
window.location = "'.str_replace('expression.php', $tab.'.php', $_SERVER["PHP_SELF"]).'?id='.$id.'";
|
||||
window.location = "'.str_replace('expression.php', $tab.'.php', $_SERVER["PHP_SELF"]).'?id='.$id.($tab == 'price' ? '&action=edit_price' : '').'";
|
||||
}
|
||||
function on_change() {
|
||||
window.location = "'.$_SERVER["PHP_SELF"].'?id='.$id.'&tab='.$tab.'&eid=" + $("#expression_selection").attr("value");
|
||||
|
||||
@@ -97,8 +97,8 @@ if (empty($reshook))
|
||||
}
|
||||
}
|
||||
|
||||
if ($action == 'updateprice' && GETPOST('cancel') <> $langs->trans("Cancel"))
|
||||
{
|
||||
if ($action == 'updateprice' && GETPOST('cancel') <> $langs->trans("Cancel"))
|
||||
{
|
||||
$id_fourn=GETPOST("id_fourn");
|
||||
if (empty($id_fourn)) $id_fourn=GETPOST("search_id_fourn");
|
||||
$ref_fourn=GETPOST("ref_fourn");
|
||||
@@ -108,7 +108,7 @@ if (empty($reshook))
|
||||
$npr = preg_match('/\*/', $_POST['tva_tx']) ? 1 : 0 ;
|
||||
$tva_tx = str_replace('*','', GETPOST('tva_tx','alpha'));
|
||||
$tva_tx = price2num($tva_tx);
|
||||
$price_expression = GETPOST('eid', 'int') == 0 ? 'NULL' : GETPOST('eid', 'int'); //Discard expression if not in expression mode
|
||||
$price_expression = GETPOST('eid', 'int') ? GETPOST('eid', 'int') : ''; // Discard expression if not in expression mode
|
||||
|
||||
if ($tva_tx == '')
|
||||
{
|
||||
@@ -132,7 +132,8 @@ if (empty($reshook))
|
||||
}
|
||||
if ($_POST["price"] < 0 || $_POST["price"] == '')
|
||||
{
|
||||
if ($price_expression == 'NULL') { //This is not because of using expression instead of numeric price
|
||||
if ($price_expression === '') // Return error of missing price only if price_expression not set
|
||||
{
|
||||
$error++;
|
||||
setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("Price")), 'errors');
|
||||
}
|
||||
@@ -189,7 +190,8 @@ if (empty($reshook))
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($price_expression != 'NULL') {
|
||||
if ($price_expression !== '')
|
||||
{
|
||||
//Check the expression validity by parsing it
|
||||
$priceparser = new PriceParser($db);
|
||||
$price_result = $priceparser->parseProductSupplier($id, $price_expression, $quantity, $tva_tx);
|
||||
@@ -410,7 +412,7 @@ if ($id || $ref)
|
||||
foreach ($price_expression->list_price_expression() as $entry) {
|
||||
$price_expression_list[$entry->id] = $entry->title;
|
||||
}
|
||||
$price_expression_preselection = GETPOST('eid') ? GETPOST('eid') : ($product->fk_price_expression ? $product->fk_price_expression : '0');
|
||||
$price_expression_preselection = GETPOST('eid') ? GETPOST('eid') : ($product->fk_supplier_price_expression ? $product->fk_supplier_price_expression : '0');
|
||||
print $form->selectarray('eid', $price_expression_list, $price_expression_preselection);
|
||||
print ' <div id="expression_editor" class="button">'.$langs->trans("PriceExpressionEditor").'</div>';
|
||||
print '</td></tr>';
|
||||
@@ -436,7 +438,7 @@ if ($id || $ref)
|
||||
}
|
||||
|
||||
// Price qty min
|
||||
print '<tr id="price_numeric"><td class="fieldrequired">'.$langs->trans("PriceQtyMin").'</td>';
|
||||
print '<tr><td class="fieldrequired">'.$langs->trans("PriceQtyMin").'</td>';
|
||||
print '<td><input class="flat" name="price" size="8" value="'.(GETPOST('price')?price(GETPOST('price')):(isset($product->fourn_price)?price($product->fourn_price):'')).'">';
|
||||
print ' ';
|
||||
print $form->select_PriceBaseType((GETPOST('price_base_type')?GETPOST('price_base_type'):$product->price_base_type), "price_base_type");
|
||||
|
||||
17
htdocs/product/index.php
Normal file → Executable file
17
htdocs/product/index.php
Normal file → Executable file
@@ -27,6 +27,7 @@
|
||||
require '../main.inc.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/priceparser.class.php';
|
||||
|
||||
$type=GETPOST("type",'int');
|
||||
if ($type =='' && !$user->rights->produit->lire) $type='1'; // Force global page on service page only
|
||||
@@ -232,7 +233,7 @@ print '</div><div class="fichetwothirdright"><div class="ficheaddleft">';
|
||||
* Last modified products
|
||||
*/
|
||||
$max=15;
|
||||
$sql = "SELECT p.rowid, p.label, p.price, p.ref, p.fk_product_type, p.tosell, p.tobuy,";
|
||||
$sql = "SELECT p.rowid, p.label, p.price, p.ref, p.fk_product_type, p.tosell, p.tobuy, p.fk_price_expression,";
|
||||
$sql.= " p.tms as datem";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
|
||||
$sql.= " WHERE p.entity IN (".getEntity($product_static->element, 1).")";
|
||||
@@ -298,9 +299,17 @@ if ($result)
|
||||
// Sell price
|
||||
if (empty($conf->global->PRODUIT_MULTIPRICES))
|
||||
{
|
||||
if (!empty($objp->fk_price_expression)) {
|
||||
$product = new Product($db);
|
||||
$product->fetch($objp->rowid);
|
||||
$priceparser = new PriceParser($db);
|
||||
$price_result = $priceparser->parseProduct($product);
|
||||
if ($price_result >= 0) {
|
||||
$objp->price = $price_result;
|
||||
}
|
||||
}
|
||||
print '<td align="right">';
|
||||
if ($objp->price_base_type == 'TTC') print price($objp->price_ttc).' '.$langs->trans("TTC");
|
||||
else print price($objp->price).' '.$langs->trans("HT");
|
||||
print price($objp->price).' '.$langs->trans("HT");
|
||||
print '</td>';
|
||||
}
|
||||
print '<td align="right" class="nowrap">';
|
||||
@@ -313,7 +322,7 @@ if ($result)
|
||||
$i++;
|
||||
}
|
||||
|
||||
$db->free();
|
||||
$db->free($result);
|
||||
|
||||
print "</table>";
|
||||
}
|
||||
|
||||
93
htdocs/product/price.php
Normal file → Executable file
93
htdocs/product/price.php
Normal file → Executable file
@@ -7,6 +7,7 @@
|
||||
* Copyright (C) 2014 Florian Henry <florian.henry@open-concept.pro>
|
||||
* Copyright (C) 2014 Juanjo Menent <jmenent@2byte.es>
|
||||
* Copyright (C) 2014 Philippe Grand <philippe.grand@atoo-net.com>
|
||||
* Copyright (C) 2014 Ion agorria <ion@agorria.com>
|
||||
*
|
||||
* 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
|
||||
@@ -30,6 +31,8 @@
|
||||
require '../main.inc.php';
|
||||
require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/class/priceexpression.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/class/priceparser.class.php';
|
||||
|
||||
if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
|
||||
@@ -72,6 +75,7 @@ if ($action == 'update_price' && ! GETPOST("cancel") && ($user->rights->produit-
|
||||
|
||||
$error=0;
|
||||
$maxpricesupplier = $object->min_recommended_price();
|
||||
$object->fk_price_expression = empty(GETPOST('eid', 'int')) ? 0 : GETPOST('eid', 'int'); //0 discards expression
|
||||
|
||||
// MultiPrix
|
||||
if (! empty($conf->global->PRODUIT_MULTIPRICES))
|
||||
@@ -114,9 +118,34 @@ if ($action == 'update_price' && ! GETPOST("cancel") && ($user->rights->produit-
|
||||
$action='edit_price';
|
||||
}
|
||||
|
||||
if ($newprice < $newprice_min && ! empty($object->fk_price_expression)) {
|
||||
$newprice = $newprice_min; //Set price same as min, the user will not see the
|
||||
}
|
||||
|
||||
if ($object->updatePrice($newprice, $newpricebase, $user, $newvat, $newprice_min, $level, $newnpr, $newpsq) > 0) {
|
||||
if ($object->fk_price_expression != 0) {
|
||||
//Check the expression validity by parsing it
|
||||
$priceparser = new PriceParser($db);
|
||||
$price_result = $priceparser->parseProduct($object);
|
||||
if ($price_result < 0) { //Expression is not valid
|
||||
$error++;
|
||||
$action='edit_price';
|
||||
setEventMessage($priceparser->translatedError(), 'errors');
|
||||
}
|
||||
}
|
||||
if (empty($error) && ! empty($conf->dynamicprices->enabled)) {
|
||||
$ret=$object->setPriceExpression($object->fk_price_expression);
|
||||
if ($ret < 0)
|
||||
{
|
||||
$error++;
|
||||
$action='edit_price';
|
||||
setEventMessage($object->error, 'errors');
|
||||
}
|
||||
}
|
||||
if (empty($error)) {
|
||||
$action = '';
|
||||
setEventMessage($langs->trans("RecordSaved"));
|
||||
}
|
||||
} else {
|
||||
$action = 'edit_price';
|
||||
setEventMessage($object->error, 'errors');
|
||||
@@ -653,15 +682,51 @@ if ($action == 'edit_price' && ($user->rights->produit->creer || $user->rights->
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
|
||||
//Only show price mode and expression selector if module is enabled
|
||||
if (! empty($conf->dynamicprices->enabled)) {
|
||||
// Price mode selector
|
||||
print '<tr><td>'.$langs->trans("PriceMode").'</td><td>';
|
||||
$price_expression = new PriceExpression($db);
|
||||
$price_expression_list = array(0 => $langs->trans("PriceNumeric")); //Put the numeric mode as first option
|
||||
foreach ($price_expression->list_price_expression() as $entry) {
|
||||
$price_expression_list[$entry->id] = $entry->title;
|
||||
}
|
||||
$price_expression_preselection = GETPOST('eid') ? GETPOST('eid') : ($object->fk_price_expression ? $object->fk_price_expression : '0');
|
||||
print $form->selectarray('eid', $price_expression_list, $price_expression_preselection);
|
||||
print ' <div id="expression_editor" class="button">'.$langs->trans("PriceExpressionEditor").'</div>';
|
||||
print '</td></tr>';
|
||||
// This code hides the numeric price input if is not selected, loads the editor page if editor button is pressed
|
||||
print '<script type="text/javascript">
|
||||
jQuery(document).ready(run);
|
||||
function run() {
|
||||
jQuery("#expression_editor").click(on_click);
|
||||
jQuery("#eid").change(on_change);
|
||||
on_change();
|
||||
}
|
||||
function on_click() {
|
||||
window.location = "'.DOL_URL_ROOT.'/product/expression.php?id='.$id.'&tab=price&eid=" + $("#eid").attr("value");
|
||||
}
|
||||
function on_change() {
|
||||
if ($("#eid").attr("value") == 0) {
|
||||
jQuery("#price_numeric").show();
|
||||
} else {
|
||||
jQuery("#price_numeric").hide();
|
||||
}
|
||||
}
|
||||
</script>';
|
||||
}
|
||||
|
||||
// Price
|
||||
print '<tr><td width="20%">';
|
||||
$product = new Product($db);
|
||||
$product->fetch($id, $ref, '', 1); //Ignore the math expression when getting the price
|
||||
print '<tr id="price_numeric"><td width="20%">';
|
||||
$text = $langs->trans('SellingPrice');
|
||||
print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1);
|
||||
print '</td><td>';
|
||||
if ($object->price_base_type == 'TTC') {
|
||||
print '<input name="price" size="10" value="' . price($object->price_ttc) . '">';
|
||||
print '<input name="price" size="10" value="' . price($product->price_ttc) . '">';
|
||||
} else {
|
||||
print '<input name="price" size="10" value="' . price($object->price) . '">';
|
||||
print '<input name="price" size="10" value="' . price($product->price) . '">';
|
||||
}
|
||||
print '</td></tr>';
|
||||
|
||||
@@ -745,7 +810,7 @@ if ($action == 'edit_price' && ($user->rights->produit->creer || $user->rights->
|
||||
// Liste des evolutions du prix
|
||||
$sql = "SELECT p.rowid, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.recuperableonly,";
|
||||
$sql .= " p.price_level, p.price_min, p.price_min_ttc,p.price_by_qty,";
|
||||
$sql .= " p.date_price as dp, u.rowid as user_id, u.login";
|
||||
$sql .= " p.date_price as dp, p.fk_price_expression, u.rowid as user_id, u.login";
|
||||
$sql .= " FROM " . MAIN_DB_PREFIX . "product_price as p,";
|
||||
$sql .= " " . MAIN_DB_PREFIX . "user as u";
|
||||
$sql .= " WHERE fk_product = " . $object->id;
|
||||
@@ -790,6 +855,9 @@ if ($result) {
|
||||
print '<td align="right">' . $langs->trans("VAT") . '</td>';
|
||||
print '<td align="right">' . $langs->trans("HT") . '</td>';
|
||||
print '<td align="right">' . $langs->trans("TTC") . '</td>';
|
||||
if (! empty($conf->dynamicprices->enabled)) {
|
||||
print '<td align="right">' . $langs->trans("PriceExpressionSelected") . '</td>';
|
||||
}
|
||||
print '<td align="right">' . $langs->trans("MinPrice") . ' ' . $langs->trans("HT") . '</td>';
|
||||
print '<td align="right">' . $langs->trans("MinPrice") . ' ' . $langs->trans("TTC") . '</td>';
|
||||
print '<td align="right">' . $langs->trans("ChangedBy") . '</td>';
|
||||
@@ -819,8 +887,25 @@ if ($result) {
|
||||
|
||||
print '<td align="center">' . $langs->trans($objp->price_base_type) . "</td>";
|
||||
print '<td align="right">' . vatrate($objp->tva_tx, true, $objp->recuperableonly) . "</td>";
|
||||
|
||||
//Price
|
||||
if (! empty($objp->fk_price_expression) && ! empty($conf->dynamicprices->enabled))
|
||||
{
|
||||
$price_expression = new PriceExpression($db);
|
||||
$res = $price_expression->fetch($objp->fk_price_expression);
|
||||
$title = $price_expression->title;
|
||||
print '<td align="right"></td>';
|
||||
print '<td align="right"></td>';
|
||||
print '<td align="right">' . $title . "</td>";
|
||||
}
|
||||
else
|
||||
{
|
||||
print '<td align="right">' . price($objp->price) . "</td>";
|
||||
print '<td align="right">' . price($objp->price_ttc) . "</td>";
|
||||
if (! empty($conf->dynamicprices->enabled)) { //Only if module is enabled
|
||||
print '<td align="right"></td>';
|
||||
}
|
||||
}
|
||||
print '<td align="right">' . price($objp->price_min) . '</td>';
|
||||
print '<td align="right">' . price($objp->price_min_ttc) . '</td>';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user