From 5bbcb58b4435a0ddd5981faa3393a3b63ac57326 Mon Sep 17 00:00:00 2001 From: Ion Agorria Date: Sun, 28 Dec 2014 01:26:41 +0100 Subject: [PATCH 1/2] Added expressions for product/service prices --- htdocs/core/boxes/box_produits.php | 44 +++++-- .../core/boxes/box_produits_alerte_stock.php | 41 +++++-- htdocs/core/class/html.form.class.php | 29 +++-- htdocs/fourn/ajax/getSupplierPrices.php | 6 +- .../fourn/class/fournisseur.product.class.php | 102 ++++++++-------- .../install/mysql/migration/3.7.0-3.8.0.sql | 4 +- htdocs/install/mysql/tables/llx_product.sql | 1 + .../tables/llx_product_fournisseur_price.sql | 2 +- .../mysql/tables/llx_product_price.sql | 1 + htdocs/langs/en_US/products.lang | 5 +- htdocs/product/class/priceparser.class.php | 111 ++++++++++++++---- htdocs/product/class/product.class.php | 72 ++++++++++-- htdocs/product/expression.php | 13 +- htdocs/product/fournisseurs.php | 15 +-- htdocs/product/index.php | 17 ++- htdocs/product/price.php | 101 ++++++++++++++-- 16 files changed, 423 insertions(+), 141 deletions(-) mode change 100644 => 100755 htdocs/core/boxes/box_produits.php mode change 100644 => 100755 htdocs/core/boxes/box_produits_alerte_stock.php mode change 100644 => 100755 htdocs/install/mysql/tables/llx_product.sql mode change 100644 => 100755 htdocs/install/mysql/tables/llx_product_price.sql mode change 100644 => 100755 htdocs/product/index.php mode change 100644 => 100755 htdocs/product/price.php diff --git a/htdocs/core/boxes/box_produits.php b/htdocs/core/boxes/box_produits.php old mode 100644 new mode 100755 index d3772ff65f1..2a9b9e984a4 --- a/htdocs/core/boxes/box_produits.php +++ b/htdocs/core/boxes/box_produits.php @@ -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,17 +106,37 @@ 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 ($objp->price_base_type == 'HT') - { - $price=price($objp->price); - $price_base_type=$langs->trans("HT"); - } - else - { - $price=price($objp->price_ttc); - $price_base_type=$langs->trans("TTC"); - } + if (empty($objp->fk_price_expression)) { + if ($objp->price_base_type == 'HT') + { + $price=price($objp->price); + $price_base_type=$langs->trans("HT"); + } + else + { + $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); diff --git a/htdocs/core/boxes/box_produits_alerte_stock.php b/htdocs/core/boxes/box_produits_alerte_stock.php old mode 100644 new mode 100755 index 1079f623492..91e2372e5c8 --- a/htdocs/core/boxes/box_produits_alerte_stock.php +++ b/htdocs/core/boxes/box_produits_alerte_stock.php @@ -114,16 +114,37 @@ class box_produits_alerte_stock extends ModeleBoxes 'text' => $objp->label, 'url' => DOL_URL_ROOT."/product/card.php?id=".$objp->rowid); - if ($objp->price_base_type == 'HT') - { - $price=price($objp->price); - $price_base_type=$langs->trans("HT"); - } - else - { - $price=price($objp->price_ttc); - $price_base_type=$langs->trans("TTC"); - } + if (empty($objp->fk_price_expression)) { + if ($objp->price_base_type == 'HT') + { + $price=price($objp->price); + $price_base_type=$langs->trans("HT"); + } + else + { + $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); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 08bc3b4c85e..678a4d57140 100755 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1522,7 +1522,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)) { @@ -1601,6 +1601,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.=''.$form->textwithpicto($langs->trans("PriceExpressionEditor"),$langs->trans("PriceExpressionEditorHelp"),1).''; +$help_text = $langs->trans("PriceExpressionEditorHelp1").'

'.$langs->trans("PriceExpressionEditorHelp2").'

'.$langs->trans("PriceExpressionEditorHelp3").'

'.$langs->trans("PriceExpressionEditorHelp4"); +print ''.$form->textwithpicto($langs->trans("PriceExpressionEditor"),$help_text,1).''; 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 ''; print ''; -// 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 ''; + } // Price - print ''; + $product = new Product($db); + $product->fetch($id, $ref, '', 1); //Ignore the math expression when getting the price + print ''; $text = $langs->trans('SellingPrice'); print $form->textwithpicto($text, $langs->trans("PrecisionUnitIsLimitedToXDecimals", $conf->global->MAIN_MAX_DECIMALS_UNIT), 1, 1); print ''; if ($object->price_base_type == 'TTC') { - print ''; + print ''; } else { - print ''; + print ''; } print ''; @@ -732,7 +797,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; @@ -777,6 +842,9 @@ if ($result) { print '' . $langs->trans("VAT") . ''; print '' . $langs->trans("HT") . ''; print '' . $langs->trans("TTC") . ''; + if (! empty($conf->dynamicprices->enabled)) { + print '' . $langs->trans("PriceExpressionSelected") . ''; + } print '' . $langs->trans("MinPrice") . ' ' . $langs->trans("HT") . ''; print '' . $langs->trans("MinPrice") . ' ' . $langs->trans("TTC") . ''; print '' . $langs->trans("ChangedBy") . ''; @@ -805,8 +873,25 @@ if ($result) { print '' . $langs->trans($objp->price_base_type) . ""; print '' . vatrate($objp->tva_tx, true, $objp->recuperableonly) . ""; - print '' . price($objp->price) . ""; - print '' . price($objp->price_ttc) . ""; + + //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 ''; + print ''; + print '' . $title . ""; + } + else + { + print '' . price($objp->price) . ""; + print '' . price($objp->price_ttc) . ""; + if (! empty($conf->dynamicprices->enabled)) { //Only if module is enabled + print ''; + } + } print '' . price($objp->price_min) . ''; print '' . price($objp->price_min_ttc) . ''; From 2c01370ce6f4dcb148e92459a094ed7e1041153a Mon Sep 17 00:00:00 2001 From: Ion Agorria Date: Wed, 21 Jan 2015 05:22:46 +0100 Subject: [PATCH 2/2] Reimplemented 'find_min_price_product_fournisseur()' --- .../fourn/class/fournisseur.product.class.php | 88 +++++++++++++------ 1 file changed, 63 insertions(+), 25 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php index dd31e64deee..76577dc9ea6 100755 --- a/htdocs/fourn/class/fournisseur.product.class.php +++ b/htdocs/fourn/class/fournisseur.product.class.php @@ -350,7 +350,7 @@ 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; @@ -476,11 +476,11 @@ class ProductFournisseur extends Product } /** - * Load properties for minimum price + * Load properties for minimum price * - * @param int $prodid Product id - * @param int $qty Minimum quantity - * @return int <0 if KO, >0 if OK, 0 if empty + * @param int $prodid Product id + * @param int $qty Minimum quantity + * @return int <0 if KO, >0 if OK */ function find_min_price_product_fournisseur($prodid, $qty=0) { @@ -498,41 +498,79 @@ class ProductFournisseur extends Product $this->fourn_name = ''; $this->id = ''; - $product_fourn_list = $this->list_product_fournisseur_price($prodid); + $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_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; dol_syslog(get_class($this)."::find_min_price_product_fournisseur", LOG_DEBUG); - if (is_array($product_fourn_list)) + $resql = $this->db->query($sql); + if ($resql) { - if (count($product_fourn_list) == 0) + $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($product_fourn_list as $productfourn) + foreach($record_array as $record) { - if ($productfourn->fourn_price < $min || $min == -1) + $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 = $productfourn->product_fourn_price_id; - $this->fourn_ref = $productfourn->fourn_ref; - $this->fourn_price = $productfourn->fourn_price; - $this->fourn_qty = $productfourn->fourn_qty; - $this->fourn_remise_percent = $productfourn->fourn_remise_percent; - $this->fourn_remise = $productfourn->fourn_remise; - $this->fourn_unitprice = $productfourn->fourn_unitprice; - $this->fourn_charges = $productfourn->fourn_charges; - $this->fourn_unitcharges = $productfourn->fourn_unitcharges; - $this->fourn_tva_tx = $productfourn->fourn_tva_tx; - $this->fourn_id = $productfourn->fourn_id; - $this->fourn_name = $productfourn->fourn_name; - $this->fk_supplier_price_expression = $productfourn->fk_supplier_price_expression; - $this->id = $productfourn->id; + $this->product_fourn_price_id = $record["product_fourn_price_id"]; + $this->fourn_ref = $record["ref_fourn"]; + $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 = $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_supplier_price_expression = $record["fk_supplier_price_expression"]; + $this->id = $prodid; + $min = $this->fourn_unitprice; } } - return 1; } + + $this->db->free($resql); + return 1; } else {