Merge pull request #457 from atm-maxime/mko559

Task # 559 : price by quantity
This commit is contained in:
Regis Houssin 2012-12-05 00:15:27 -08:00
commit 644a05f6dc
12 changed files with 708 additions and 157 deletions

View File

@ -1153,6 +1153,18 @@ class Form
{ {
$sql.= ", pl.label as label_translated"; $sql.= ", pl.label as label_translated";
} }
// Price by quantity
if (! empty($conf->global->PRODUIT_PRICE_BY_QTY))
{
$sql.= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
if ($price_level >= 1) $sql.= " AND price_level=".$price_level;
$sql.= " ORDER BY date_price";
$sql.= " DESC LIMIT 1) as price_rowid";
$sql.= ", (SELECT pp.price_by_qty FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
if ($price_level >= 1) $sql.= " AND price_level=".$price_level;
$sql.= " ORDER BY date_price";
$sql.= " DESC LIMIT 1) as price_by_qty";
}
$sql.= " FROM ".MAIN_DB_PREFIX."product as p"; $sql.= " FROM ".MAIN_DB_PREFIX."product as p";
// Multilang : we add translation // Multilang : we add translation
if (! empty($conf->global->MAIN_MULTILANGS)) if (! empty($conf->global->MAIN_MULTILANGS))
@ -1214,137 +1226,51 @@ class Form
$i = 0; $i = 0;
while ($num && $i < $num) while ($num && $i < $num)
{ {
$outkey=''; $opt = '';
$outval=''; $optJson = array();
$outref=''; $objp = $this->db->fetch_object($result);
$outlabel='';
$outdesc='';
$outtype='';
$outprice_ht='';
$outprice_ttc='';
$outpricebasetype='';
$outtva_tx='';
$objp = $this->db->fetch_object($result); if(!empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product
$sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
$sql.= " WHERE fk_product_price=".$objp->price_rowid;
$sql.= " ORDER BY quantity ASC";
$label=$objp->label; dol_syslog(get_class($this)."::select_produits_do search price by qty sql=".$sql);
if (! empty($objp->label_translated)) $label=$objp->label_translated; $result2 = $this->db->query($sql);
if ($filterkey && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$label,1); if ($result2)
{
$nb_prices = $this->db->num_rows($result2);
$j = 0;
while ($nb_prices && $j < $nb_prices) {
$objp2 = $this->db->fetch_object($result2);
$outkey=$objp->rowid; $objp->quantity = $objp2->quantity;
$outref=$objp->ref; $objp->price = $objp2->price;
$outlabel=$objp->label; $objp->unitprice = $objp2->unitprice;
$outdesc=$objp->description; $objp->remise_percent = $objp2->remise_percent;
$outtype=$objp->fk_product_type; $objp->remise = $objp2->remise;
$objp->price_by_qty_rowid = $objp2->rowid;
$opt = '<option value="'.$objp->rowid.'"'; $this->_construct_product_list_option($objp, $opt, $optJson, 0, $selected);
$opt.= ($objp->rowid == $selected)?' selected="selected"':'';
if (! empty($conf->stock->enabled) && $objp->fk_product_type == 0 && isset($objp->stock))
{
if ($objp->stock > 0) $opt.= ' class="product_line_stock_ok"';
else if ($objp->stock <= 0) $opt.= ' class="product_line_stock_too_low"';
}
$opt.= '>';
$opt.= $objp->ref.' - '.dol_trunc($label,32).' - ';
$objRef = $objp->ref; $j++;
if ($filterkey && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
$outval.=$objRef.' - '.dol_trunc($label,32).' - ';
$found=0; // Add new entry
$currencytext=$langs->trans("Currency".$conf->currency); // "key" value of json key array is used by jQuery automatically as selected value
$currencytextnoent=$langs->transnoentities("Currency".$conf->currency); // "label" value of json key array is used by jQuery automatically as text for combo box
if (dol_strlen($currencytext) > 10) $currencytext=$conf->currency; // If text is too long, we use the short code $outselect.=$opt;
if (dol_strlen($currencytextnoent) > 10) $currencytextnoent=$conf->currency; // If text is too long, we use the short code array_push($outjson, $optJson);
}
// Multiprice }
if ($price_level >= 1) // If we need a particular price level (from 1 to 6) } else {
{ $this->_construct_product_list_option($objp, $opt, $optJson, $price_level, $selected);
$sql = "SELECT price, price_ttc, price_base_type, tva_tx"; // Add new entry
$sql.= " FROM ".MAIN_DB_PREFIX."product_price"; // "key" value of json key array is used by jQuery automatically as selected value
$sql.= " WHERE fk_product='".$objp->rowid."'"; // "label" value of json key array is used by jQuery automatically as text for combo box
$sql.= " AND price_level=".$price_level; $outselect.=$opt;
$sql.= " ORDER BY date_price"; array_push($outjson, $optJson);
$sql.= " DESC LIMIT 1"; }
dol_syslog(get_class($this)."::select_produits_do search price for level '.$price_level.' sql=".$sql);
$result2 = $this->db->query($sql);
if ($result2)
{
$objp2 = $this->db->fetch_object($result2);
if ($objp2)
{
$found=1;
if ($objp2->price_base_type == 'HT')
{
$opt.= price($objp2->price,1).' '.$currencytext.' '.$langs->trans("HT");
$outval.= price($objp2->price,1).' '.$currencytextnoent.' '.$langs->transnoentities("HT");
}
else
{
$opt.= price($objp2->price_ttc,1).' '.$currencytext.' '.$langs->trans("TTC");
$outval.= price($objp2->price_ttc,1).' '.$currencytextnoent.' '.$langs->transnoentities("TTC");
}
$outprice_ht=price($objp2->price);
$outprice_ttc=price($objp2->price_ttc);
$outpricebasetype=$objp2->price_base_type;
$outtva_tx=$objp2->tva_tx;
}
}
else
{
dol_print_error($this->db);
}
}
// If level no defined or multiprice not found, we used the default price
if (! $found)
{
if ($objp->price_base_type == 'HT')
{
$opt.= price($objp->price,1).' '.$currencytext.' '.$langs->trans("HT");
$outval.= price($objp->price,1).' '.$currencytextnoent.' '.$langs->transnoentities("HT");
}
else
{
$opt.= price($objp->price_ttc,1).' '.$currencytext.' '.$langs->trans("TTC");
$outval.= price($objp->price_ttc,1).' '.$currencytextnoent.' '.$langs->transnoentities("TTC");
}
$outprice_ht=price($objp->price);
$outprice_ttc=price($objp->price_ttc);
$outpricebasetype=$objp->price_base_type;
$outtva_tx=$objp->tva_tx;
}
if (! empty($conf->stock->enabled) && isset($objp->stock) && $objp->fk_product_type == 0)
{
$opt.= ' - '.$langs->trans("Stock").':'.$objp->stock;
$outval.=' - '.$langs->transnoentities("Stock").':'.$objp->stock;
}
if ($objp->duration)
{
$duration_value = substr($objp->duration,0,dol_strlen($objp->duration)-1);
$duration_unit = substr($objp->duration,-1);
if ($duration_value > 1)
{
$dur=array("h"=>$langs->trans("Hours"),"d"=>$langs->trans("Days"),"w"=>$langs->trans("Weeks"),"m"=>$langs->trans("Months"),"y"=>$langs->trans("Years"));
}
else
{
$dur=array("h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year"));
}
$opt.= ' - '.$duration_value.' '.$langs->trans($dur[$duration_unit]);
$outval.=' - '.$duration_value.' '.$langs->transnoentities($dur[$duration_unit]);
}
$opt.= "</option>\n";
// Add new entry
// "key" value of json key array is used by jQuery automatically as selected value
// "label" value of json key array is used by jQuery automatically as text for combo box
$outselect.=$opt;
array_push($outjson, array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx));
$i++; $i++;
} }
@ -1362,6 +1288,174 @@ class Form
} }
} }
function _construct_product_list_option(&$objp, &$opt, &$optJson, $price_level, $selected) {
global $langs,$conf,$user,$db;
$outkey='';
$outval='';
$outref='';
$outlabel='';
$outdesc='';
$outtype='';
$outprice_ht='';
$outprice_ttc='';
$outpricebasetype='';
$outtva_tx='';
$outqty=1;
$outdiscount=0;
$label=$objp->label;
if (! empty($objp->label_translated)) $label=$objp->label_translated;
if ($filterkey && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$label,1);
$outkey=$objp->rowid;
$outref=$objp->ref;
$outlabel=$objp->label;
$outdesc=$objp->description;
$outtype=$objp->fk_product_type;
$opt = '<option value="'.$objp->rowid.'"';
$opt.= ($objp->rowid == $selected)?' selected="selected"':'';
$opt.= (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0)?' pbq="'.$objp->price_by_qty_rowid.'"':'';
if (! empty($conf->stock->enabled) && $objp->fk_product_type == 0 && isset($objp->stock))
{
if ($objp->stock > 0) $opt.= ' class="product_line_stock_ok"';
else if ($objp->stock <= 0) $opt.= ' class="product_line_stock_too_low"';
}
$opt.= '>';
$opt.= $objp->ref.' - '.dol_trunc($label,32).' - ';
$objRef = $objp->ref;
if ($filterkey && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
$outval.=$objRef.' - '.dol_trunc($label,32).' - ';
$found=0;
$currencytext=$langs->trans("Currency".$conf->currency);
$currencytextnoent=$langs->transnoentities("Currency".$conf->currency);
if (dol_strlen($currencytext) > 10) $currencytext=$conf->currency; // If text is too long, we use the short code
if (dol_strlen($currencytextnoent) > 10) $currencytextnoent=$conf->currency; // If text is too long, we use the short code
// Multiprice
if ($price_level >= 1) // If we need a particular price level (from 1 to 6)
{
$sql = "SELECT price, price_ttc, price_base_type, tva_tx";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price";
$sql.= " WHERE fk_product='".$objp->rowid."'";
$sql.= " AND price_level=".$price_level;
$sql.= " ORDER BY date_price";
$sql.= " DESC LIMIT 1";
dol_syslog(get_class($this)."::select_produits_do search price for level '.$price_level.' sql=".$sql);
$result2 = $this->db->query($sql);
if ($result2)
{
$objp2 = $this->db->fetch_object($result2);
if ($objp2)
{
$found=1;
if ($objp2->price_base_type == 'HT')
{
$opt.= price($objp2->price,1).' '.$currencytext.' '.$langs->trans("HT");
$outval.= price($objp2->price,1).' '.$currencytextnoent.' '.$langs->transnoentities("HT");
}
else
{
$opt.= price($objp2->price_ttc,1).' '.$currencytext.' '.$langs->trans("TTC");
$outval.= price($objp2->price_ttc,1).' '.$currencytextnoent.' '.$langs->transnoentities("TTC");
}
$outprice_ht=price($objp2->price);
$outprice_ttc=price($objp2->price_ttc);
$outpricebasetype=$objp2->price_base_type;
$outtva_tx=$objp2->tva_tx;
}
}
else
{
dol_print_error($this->db);
}
}
// Price by quantity
if (!empty($objp->quantity) && $objp->quantity >= 1) {
$found = 1;
$outqty=$objp->quantity;
$outdiscount=$objp->remise_percent;
if ($objp->quantity == 1)
{
$opt.= price($objp->unitprice).' '.$currencytext."/";
$outval.= price($objp->unitprice).' '.$currencytextnoent."/";
$opt.= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
$outval.=$langs->transnoentities("Unit");
}
else
{
$opt.= price($objp->price).' '.$currencytext."/".$objp->quantity;
$outval.= price($objp->price).' '.$currencytextnoent."/".$objp->quantity;
$opt.= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
$outval.=$langs->transnoentities("Units");
}
$outprice_ht=price($objp->unitprice);
$outprice_ttc=price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
$outpricebasetype=$objp->price_base_type;
$outtva_tx=$objp->tva_tx;
}
if (!empty($objp->quantity) && $objp->quantity >= 1)
{
$opt.=" (".price($objp->unitprice).' '.$currencytext."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
$outval.=" (".price($objp->unitprice).' '.$currencytextnoent."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
}
if (!empty($objp->remise_percent) && $objp->remise_percent >= 1)
{
$opt.=" - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
$outval.=" - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
}
// If level no defined or multiprice not found, we used the default price
if (! $found)
{
if ($objp->price_base_type == 'HT')
{
$opt.= price($objp->price,1).' '.$currencytext.' '.$langs->trans("HT");
$outval.= price($objp->price,1).' '.$currencytextnoent.' '.$langs->transnoentities("HT");
}
else
{
$opt.= price($objp->price_ttc,1).' '.$currencytext.' '.$langs->trans("TTC");
$outval.= price($objp->price_ttc,1).' '.$currencytextnoent.' '.$langs->transnoentities("TTC");
}
$outprice_ht=price($objp->price);
$outprice_ttc=price($objp->price_ttc);
$outpricebasetype=$objp->price_base_type;
$outtva_tx=$objp->tva_tx;
}
if (! empty($conf->stock->enabled) && isset($objp->stock) && $objp->fk_product_type == 0)
{
$opt.= ' - '.$langs->trans("Stock").':'.$objp->stock;
$outval.=' - '.$langs->transnoentities("Stock").':'.$objp->stock;
}
if ($objp->duration)
{
$duration_value = substr($objp->duration,0,dol_strlen($objp->duration)-1);
$duration_unit = substr($objp->duration,-1);
if ($duration_value > 1)
{
$dur=array("h"=>$langs->trans("Hours"),"d"=>$langs->trans("Days"),"w"=>$langs->trans("Weeks"),"m"=>$langs->trans("Months"),"y"=>$langs->trans("Years"));
}
else
{
$dur=array("h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year"));
}
$opt.= ' - '.$duration_value.' '.$langs->trans($dur[$duration_unit]);
$outval.=' - '.$duration_value.' '.$langs->transnoentities($dur[$duration_unit]);
}
$opt.= "</option>\n";
$optJson = array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount);
}
/** /**
* Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_do) * Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_do)
* *
@ -1536,7 +1630,7 @@ class Form
} }
} }
else else
{ {
$opt.= $langs->trans("NoPriceDefinedForThisSupplier"); $opt.= $langs->trans("NoPriceDefinedForThisSupplier");
$outval.=$langs->transnoentities("NoPriceDefinedForThisSupplier"); $outval.=$langs->transnoentities("NoPriceDefinedForThisSupplier");
} }

View File

@ -79,7 +79,9 @@ if (! empty($conf->margin->enabled)) {
'price_ht' => 'price_ht', 'price_ht' => 'price_ht',
'origin_price_ht_cache' => 'price_ht', 'origin_price_ht_cache' => 'price_ht',
'origin_tva_tx_cache' => 'tva_tx', 'origin_tva_tx_cache' => 'tva_tx',
'origin_price_ttc_cache' => 'price_ttc' 'origin_price_ttc_cache' => 'price_ttc',
'qty' => 'qty',
'remise_percent' => 'discount'
), ),
'update_textarea' => array( 'update_textarea' => array(
'product_desc' => 'desc' 'product_desc' => 'desc'
@ -158,7 +160,7 @@ if (! empty($conf->margin->enabled)) {
<input type="hidden" id="origin_price_ttc_cache" name="origin_price_ttc_cache" value="" /> <input type="hidden" id="origin_price_ttc_cache" name="origin_price_ttc_cache" value="" />
</td> </td>
<td align="right"><input type="text" size="3" id="qty" name="qty" value="<?php echo (GETPOST('qty')?GETPOST('qty'):1); ?>"></td> <td align="right"><input type="text" size="3" id="qty" name="qty" value="<?php echo (GETPOST('qty')?GETPOST('qty'):1); ?>"></td>
<td align="right" nowrap="nowrap"><input type="text" size="1" value="<?php echo $buyer->remise_client; ?>" name="remise_percent">%</td> <td align="right" nowrap="nowrap"><input type="text" size="1" value="<?php echo $buyer->remise_client; ?>" id="remise_percent" name="remise_percent">%</td>
<?php <?php
$colspan = 4; $colspan = 4;
if (! empty($conf->margin->enabled)) { if (! empty($conf->margin->enabled)) {
@ -225,7 +227,9 @@ $(document).ready(function() {
$.post('<?php echo DOL_URL_ROOT; ?>/product/ajax/products.php', { $.post('<?php echo DOL_URL_ROOT; ?>/product/ajax/products.php', {
'action': 'fetch', 'action': 'fetch',
'id': $(this).val(), 'id': $(this).val(),
'price_level': <?php echo empty($buyer->price_level)?1:$buyer->price_level; ?>}, 'price_level': <?php echo empty($buyer->price_level)?1:$buyer->price_level; ?>,
'pbq': $("option:selected", this).attr('pbq')
},
function(data) { function(data) {
if (typeof data != 'undefined') { if (typeof data != 'undefined') {
$('#product_ref').val(data.ref); $('#product_ref').val(data.ref);
@ -237,6 +241,8 @@ $(document).ready(function() {
$('#origin_tva_tx_cache').val(data.tva_tx); $('#origin_tva_tx_cache').val(data.tva_tx);
$('#select_type').val(data.type).attr('disabled','disabled').trigger('change'); $('#select_type').val(data.type).attr('disabled','disabled').trigger('change');
//$('#price_base_type_area').show(); //$('#price_base_type_area').show();
$('#qty').val(data.qty);
$('#remise_percent').val(data.discount);
if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances['product_desc'] != "undefined") { if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances['product_desc'] != "undefined") {
CKEDITOR.instances['product_desc'].setData(data.desc).focus(); CKEDITOR.instances['product_desc'].setData(data.desc).focus();

View File

@ -801,6 +801,28 @@ ALTER TABLE llx_categorie ADD UNIQUE INDEX uk_categorie_ref (entity, fk_parent,
ALTER TABLE llx_categorie ADD INDEX idx_categorie_type (type); ALTER TABLE llx_categorie ADD INDEX idx_categorie_type (type);
ALTER TABLE llx_categorie ADD INDEX idx_categorie_label (label); ALTER TABLE llx_categorie ADD INDEX idx_categorie_label (label);
-- [ task #559 ] Price by quantity management
CREATE TABLE llx_product_price_by_qty
(
rowid integer AUTO_INCREMENT PRIMARY KEY,
fk_product_price integer NOT NULL,
date_price timestamp,
price double (24,8) DEFAULT 0,
price_ttc double (24,8) DEFAULT 0,
qty_min real DEFAULT 0
)ENGINE=innodb;
ALTER TABLE llx_product_price ADD price_by_qty INT NOT NULL DEFAULT 0;
ALTER TABLE llx_product_price_by_qty ADD UNIQUE INDEX uk_product_price_by_qty_level (fk_product_price, qty_min);
ALTER TABLE llx_product_price_by_qty ADD INDEX idx_product_price_by_qty_fk_product_price (fk_product_price);
ALTER TABLE llx_product_price_by_qty ADD CONSTRAINT fk_product_price_by_qty_fk_product_price FOREIGN KEY (fk_product_price) REFERENCES llx_product_price (rowid);
ALTER TABLE `llx_product_price_by_qty` ADD `remise_percent` DOUBLE NOT NULL DEFAULT '0' AFTER `price_ttc` ,
ADD `remise` DOUBLE NOT NULL DEFAULT '0' AFTER `remise_percent`;
-- Change index name to be compliant with SQL standard, index name must be unique in database schema -- Change index name to be compliant with SQL standard, index name must be unique in database schema
ALTER TABLE llx_c_actioncomm DROP INDEX code, ADD UNIQUE uk_c_actioncomm (code); ALTER TABLE llx_c_actioncomm DROP INDEX code, ADD UNIQUE uk_c_actioncomm (code);
ALTER TABLE llx_c_civilite DROP INDEX code, ADD UNIQUE uk_c_civilite (code); ALTER TABLE llx_c_civilite DROP INDEX code, ADD UNIQUE uk_c_civilite (code);
@ -811,13 +833,11 @@ ALTER TABLE llx_c_typent DROP INDEX code, ADD UNIQUE uk_c_typent (code);
ALTER TABLE llx_c_effectif DROP INDEX code, ADD UNIQUE uk_c_effectif (code); ALTER TABLE llx_c_effectif DROP INDEX code, ADD UNIQUE uk_c_effectif (code);
ALTER TABLE llx_c_paiement DROP INDEX code, ADD UNIQUE uk_c_paiement (code); ALTER TABLE llx_c_paiement DROP INDEX code, ADD UNIQUE uk_c_paiement (code);
delete from llx_c_actioncomm where id = 40; delete from llx_c_actioncomm where id = 40;
INSERT INTO llx_c_actioncomm (id, code, type, libelle, module, position) values ( 40, 'AC_OTH_AUTO','systemauto', 'Other (automatically inserted events)' ,NULL, 20); INSERT INTO llx_c_actioncomm (id, code, type, libelle, module, position) values ( 40, 'AC_OTH_AUTO','systemauto', 'Other (automatically inserted events)' ,NULL, 20);
UPDATE llx_c_actioncomm SET libelle = 'Other (manually inserted events)' WHERE code = 'AC_OTH'; UPDATE llx_c_actioncomm SET libelle = 'Other (manually inserted events)' WHERE code = 'AC_OTH';
UPDATE llx_c_actioncomm SET active = 0 WHERE code in ('AC_PROP', 'AC_COM', 'AC_FAC', 'AC_SHIP', 'AC_SUP_ORD', 'AC_SUP_INV'); UPDATE llx_c_actioncomm SET active = 0 WHERE code in ('AC_PROP', 'AC_COM', 'AC_FAC', 'AC_SHIP', 'AC_SUP_ORD', 'AC_SUP_INV');
-- Update dictionnary of table llx_c_paper_format -- Update dictionnary of table llx_c_paper_format
DELETE FROM llx_c_paper_format; DELETE FROM llx_c_paper_format;
@ -850,8 +870,6 @@ INSERT INTO llx_c_paper_format (rowid, code, label, width, height, unit, active)
-- increase field size -- increase field size
ALTER TABLE llx_bank_account MODIFY COLUMN code_banque varchar(8); ALTER TABLE llx_bank_account MODIFY COLUMN code_banque varchar(8);
create table llx_user_extrafields create table llx_user_extrafields
( (
rowid integer AUTO_INCREMENT PRIMARY KEY, rowid integer AUTO_INCREMENT PRIMARY KEY,
@ -861,4 +879,3 @@ create table llx_user_extrafields
)ENGINE=innodb; )ENGINE=innodb;
ALTER TABLE llx_user_extrafields ADD INDEX idx_user_extrafields (fk_object); ALTER TABLE llx_user_extrafields ADD INDEX idx_user_extrafields (fk_object);

View File

@ -31,6 +31,8 @@ create table llx_product_fournisseur_price
fk_availability integer, fk_availability integer,
price double(24,8) DEFAULT 0, price double(24,8) DEFAULT 0,
quantity double, quantity double,
remise_percent double NOT NULL DEFAULT 0,
remise double NOT NULL DEFAULT 0,
unitprice double(24,8) DEFAULT 0, unitprice double(24,8) DEFAULT 0,
charges double(24,8) DEFAULT 0, charges double(24,8) DEFAULT 0,
unitcharges double(24,8) DEFAULT 0, unitcharges double(24,8) DEFAULT 0,

View File

@ -36,6 +36,7 @@ create table llx_product_price
localtax1_tx double(6,3) DEFAULT 0, localtax1_tx double(6,3) DEFAULT 0,
localtax2_tx double(6,3) DEFAULT 0, localtax2_tx double(6,3) DEFAULT 0,
fk_user_author integer, fk_user_author integer,
tosell tinyint DEFAULT 1 tosell tinyint DEFAULT 1,
price_by_qty integer NOT NULL DEFAULT 0
)ENGINE=innodb; )ENGINE=innodb;

View File

@ -0,0 +1,26 @@
-- ============================================================================
-- Copyright (C) 2002-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Copyright (C) 2005-2012 Regis Houssin <regis@dolibarr.fr>
-- Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
-- Copyright (C) 2012 Maxime Kohlhaas <maxime.kohlhaas@atm-consulting.fr>
--
-- 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 2 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 <http://www.gnu.org/licenses/>.
--
-- ============================================================================
ALTER TABLE llx_product_price_by_qty ADD UNIQUE INDEX uk_product_price_by_qty_level (fk_product_price, quantity);
ALTER TABLE llx_product_price_by_qty ADD INDEX idx_product_price_by_qty_fk_product_price (fk_product_price);
ALTER TABLE llx_product_price_by_qty ADD CONSTRAINT fk_product_price_by_qty_fk_product_price FOREIGN KEY (fk_product_price) REFERENCES llx_product_price (rowid);

View File

@ -0,0 +1,32 @@
-- ============================================================================
-- Copyright (C) 2002-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Copyright (C) 2005-2012 Regis Houssin <regis@dolibarr.fr>
-- Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
-- Copyright (C) 2012 Maxime Kohlhaas <maxime.kohlhaas@atm-consulting.fr>
--
-- 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 2 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 <http://www.gnu.org/licenses/>.
--
-- ============================================================================
create table llx_product_price_by_qty
(
rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,
fk_product_price integer NOT NULL,
date_price timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
price double(24,8) DEFAULT 0,
quantity double DEFAULT NULL,
remise_percent double NOT NULL DEFAULT 0,
remise double NOT NULL DEFAULT 0,
unitprice double(24,8) DEFAULT 0
)ENGINE=innodb;

View File

@ -181,3 +181,5 @@ HelpAddThisServiceCard=This option allows you to create or clone a service if it
CurrentProductPrice=Current price CurrentProductPrice=Current price
AlwaysUseNewPrice=Always use current price of product/service AlwaysUseNewPrice=Always use current price of product/service
AlwaysUseFixedPrice=Use the fixed price AlwaysUseFixedPrice=Use the fixed price
PriceByQuantity=Price by quantity
PriceByQuantityRange=Quantity range

View File

@ -181,3 +181,5 @@ HelpAddThisServiceCard=Cette option permet de créer ou de cloner une fiche serv
CurrentProductPrice=Prix actuel CurrentProductPrice=Prix actuel
AlwaysUseNewPrice=Toujours utiliser le prix du jour AlwaysUseNewPrice=Toujours utiliser le prix du jour
AlwaysUseFixedPrice=Utiliser le prix fixé AlwaysUseFixedPrice=Utiliser le prix fixé
PriceByQuantity=Prix par quantité
PriceByQuantityRange=Grille de quantités

View File

@ -38,9 +38,10 @@ $type=GETPOST('type','int');
$mode=GETPOST('mode','int'); $mode=GETPOST('mode','int');
$status=((GETPOST('status','int') >= 0) ? GETPOST('status','int') : -1); $status=((GETPOST('status','int') >= 0) ? GETPOST('status','int') : -1);
$outjson=(GETPOST('outjson','int') ? GETPOST('outjson','int') : 0); $outjson=(GETPOST('outjson','int') ? GETPOST('outjson','int') : 0);
$pricelevel=GETPOST('price_level','int'); $price_level=GETPOST('price_level','int');
$action=GETPOST('action', 'alpha'); $action=GETPOST('action', 'alpha');
$id=GETPOST('id', 'int'); $id=GETPOST('id', 'int');
$price_by_qty_rowid=GETPOST('pbq', 'int');
/* /*
* View * View
@ -65,11 +66,37 @@ if (! empty($action) && $action == 'fetch' && ! empty($id))
$outlabel=$object->label; $outlabel=$object->label;
$outdesc=$object->description; $outdesc=$object->description;
$outtype=$object->type; $outtype=$object->type;
$outqty=1;
$outdiscount=0;
$found=false; $found=false;
// Price by qty
if (!empty($price_by_qty_rowid) && $price_by_qty_rowid >= 1) // If we need a particular price related to qty
{
$sql = "SELECT price, unitprice, quantity, remise_percent";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty ";
$sql.= " WHERE rowid=".$price_by_qty_rowid."";
$result = $db->query($sql);
if ($result)
{
$objp = $db->fetch_object($result);
if ($objp)
{
$found=true;
$outprice_ht=price($objp->unitprice);
$outprice_ttc=price($objp->unitprice * (1 + ($object->tva_tx / 100)));
$outpricebasetype=$object->price_base_type;
$outtva_tx=$object->tva_tx;
$outqty=$objp->quantity;
$outdiscount=$objp->remise_percent;
}
}
}
// Multiprice // Multiprice
if (isset($price_level) && $price_level >= 1) // If we need a particular price level (from 1 to 6) if (! $found && isset($price_level) && $price_level >= 1) // If we need a particular price level (from 1 to 6)
{ {
$sql = "SELECT price, price_ttc, price_base_type, tva_tx"; $sql = "SELECT price, price_ttc, price_base_type, tva_tx";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price "; $sql.= " FROM ".MAIN_DB_PREFIX."product_price ";
@ -78,10 +105,10 @@ if (! empty($action) && $action == 'fetch' && ! empty($id))
$sql.= " ORDER BY date_price"; $sql.= " ORDER BY date_price";
$sql.= " DESC LIMIT 1"; $sql.= " DESC LIMIT 1";
$result = $this->db->query($sql); $result = $db->query($sql);
if ($result) if ($result)
{ {
$objp = $this->db->fetch_object($result); $objp = $db->fetch_object($result);
if ($objp) if ($objp)
{ {
$found=true; $found=true;
@ -101,7 +128,7 @@ if (! empty($action) && $action == 'fetch' && ! empty($id))
$outtva_tx=$object->tva_tx; $outtva_tx=$object->tva_tx;
} }
$outjson = array('ref'=>$outref, 'label'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx); $outjson = array('ref'=>$outref, 'label'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount);
} }
echo json_encode($outjson); echo json_encode($outjson);

View File

@ -61,6 +61,11 @@ class Product extends CommonObject
var $multiprices_ttc=array(); var $multiprices_ttc=array();
var $multiprices_base_type=array(); var $multiprices_base_type=array();
var $multiprices_tva_tx=array(); var $multiprices_tva_tx=array();
//! Price by quantity arrays
var $price_by_qty;
var $prices_by_qty=array();
var $prices_by_qty_id=array();
var $prices_by_qty_list=array();
//! Default VAT rate of product //! Default VAT rate of product
var $tva_tx; var $tva_tx;
//! French VAT NPR (0 or 1) //! French VAT NPR (0 or 1)
@ -214,6 +219,10 @@ class Product extends CommonObject
if (empty($this->price)) $this->price = 0; if (empty($this->price)) $this->price = 0;
if (empty($this->price_min)) $this->price_min = 0; if (empty($this->price_min)) $this->price_min = 0;
// Price by quantity
if (empty($this->price_by_qty)) $this->price_by_qty = 0;
if (empty($this->status)) $this->status = 0; if (empty($this->status)) $this->status = 0;
if (empty($this->status_buy)) $this->status_buy = 0; if (empty($this->status_buy)) $this->status_buy = 0;
if (empty($this->finished)) $this->finished = 0; if (empty($this->finished)) $this->finished = 0;
@ -806,9 +815,9 @@ class Product extends CommonObject
// Add new price // 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 = "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) "; $sql.= " localtax1_tx, localtax2_tx, price_min,price_min_ttc,price_by_qty) ";
$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.= " 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; $sql.= " ".$this->localtax1_tx.",".$this->localtax2_tx.",".$this->price_min.",".$this->price_min_ttc.",".$this->price_by_qty;
$sql.= ")"; $sql.= ")";
dol_syslog(get_class($this)."_log_price sql=".$sql); dol_syslog(get_class($this)."_log_price sql=".$sql);
@ -945,9 +954,10 @@ class Product extends CommonObject
* @param double $newminprice New price min * @param double $newminprice New price min
* @param int $level 0=standard, >0 = level if multilevel prices * @param int $level 0=standard, >0 = level if multilevel prices
* @param int $newnpr 0=Standard vat rate, 1=Special vat rate for French NPR VAT * @param int $newnpr 0=Standard vat rate, 1=Special vat rate for French NPR VAT
* @param int $newpsq 1 if it has price by quantity
* @return int <0 if KO, >0 if OK * @return int <0 if KO, >0 if OK
*/ */
function updatePrice($id, $newprice, $newpricebase, $user, $newvat='',$newminprice='', $level=0, $newnpr=0) function updatePrice($id, $newprice, $newpricebase, $user, $newvat='',$newminprice='', $level=0, $newnpr=0, $newpsq=0)
{ {
global $conf,$langs; global $conf,$langs;
@ -1036,6 +1046,9 @@ class Product extends CommonObject
$this->localtax1_tx = $localtax1; $this->localtax1_tx = $localtax1;
$this->localtax2_tx = $localtax2; $this->localtax2_tx = $localtax2;
// Price by quantity
$this->price_by_qty = $newpsq;
$this->_log_price($user,$level); $this->_log_price($user,$level);
// Appel des triggers // Appel des triggers
@ -1170,7 +1183,7 @@ class Product extends CommonObject
for ($i=1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) for ($i=1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++)
{ {
$sql = "SELECT price, price_ttc, price_min, price_min_ttc,"; $sql = "SELECT price, price_ttc, price_min, price_min_ttc,";
$sql.= " price_base_type, tva_tx, tosell"; $sql.= " price_base_type, tva_tx, tosell, price_by_qty, rowid";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price";
$sql.= " WHERE price_level=".$i; $sql.= " WHERE price_level=".$i;
$sql.= " AND fk_product = '".$this->id."'"; $sql.= " AND fk_product = '".$this->id."'";
@ -1187,6 +1200,40 @@ class Product extends CommonObject
$this->multiprices_min_ttc[$i]=$result["price_min_ttc"]; $this->multiprices_min_ttc[$i]=$result["price_min_ttc"];
$this->multiprices_base_type[$i]=$result["price_base_type"]; $this->multiprices_base_type[$i]=$result["price_base_type"];
$this->multiprices_tva_tx[$i]=$result["tva_tx"]; $this->multiprices_tva_tx[$i]=$result["tva_tx"];
// Price by quantity
$this->prices_by_qty[$i]=$result["price_by_qty"];
$this->prices_by_qty_id[$i]=$result["rowid"];
// Récuperation de la liste des prix selon qty si flag positionné
if ($this->prices_by_qty[$i] == 1)
{
$sql = "SELECT rowid,price, unitprice, quantity, remise_percent, remise";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
$sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[$i]."'";
$sql.= " ORDER BY quantity ASC";
$resultat=array();
$resql = $this->db->query($sql) ;
if ($resql)
{
$ii=0;
while ($result= $this->db->fetch_array($resql)) {
$resultat[$ii]=array();
$resultat[$ii]["rowid"]=$result["rowid"];
$resultat[$ii]["price"]= $result["price"];
$resultat[$ii]["unitprice"]= $result["unitprice"];
$resultat[$ii]["quantity"]= $result["quantity"];
$resultat[$ii]["remise_percent"]= $result["remise_percent"];
$resultat[$ii]["remise"]= $result["remise"];
$ii++;
}
$this->prices_by_qty_list[$i]=$resultat;
}
else
{
dol_print_error($this->db);
return -1;
}
}
} }
else else
{ {
@ -1194,6 +1241,58 @@ class Product extends CommonObject
return -1; return -1;
} }
} }
} else if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY))
{
$sql = "SELECT price, price_ttc, price_min, price_min_ttc,";
$sql.= " price_base_type, tva_tx, tosell, price_by_qty, rowid";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price";
$sql.= " WHERE fk_product = '".$this->id."'";
$sql.= " ORDER BY date_price DESC";
$sql.= " LIMIT 1";
$resql = $this->db->query($sql);
if ($resql)
{
$result = $this->db->fetch_array($resql);
// Price by quantity
$this->prices_by_qty[0]=$result["price_by_qty"];
$this->prices_by_qty_id[0]=$result["rowid"];
// Récuperation de la liste des prix selon qty si flag positionné
if ($this->prices_by_qty[0] == 1)
{
$sql = "SELECT rowid,price, unitprice, quantity, remise_percent, remise";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
$sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[0]."'";
$sql.= " ORDER BY quantity ASC";
$resultat=array();
$resql = $this->db->query($sql) ;
if ($resql)
{
$ii=0;
while ($result= $this->db->fetch_array($resql)) {
$resultat[$ii]=array();
$resultat[$ii]["rowid"]=$result["rowid"];
$resultat[$ii]["price"]= $result["price"];
$resultat[$ii]["unitprice"]= $result["unitprice"];
$resultat[$ii]["quantity"]= $result["quantity"];
$resultat[$ii]["remise_percent"]= $result["remise_percent"];
$resultat[$ii]["remise"]= $result["remise"];
$ii++;
}
$this->prices_by_qty_list[0]=$resultat;
}
else
{
dol_print_error($this->db);
return -1;
}
}
}
else
{
dol_print_error($this->db);
return -1;
}
} }
$res=$this->load_stock(); $res=$this->load_stock();

View File

@ -70,6 +70,8 @@ if ($action == 'update_price' && ! $_POST["cancel"] && ($user->rights->produit->
$newpricebase=$_POST["multiprices_base_type_".$i]; $newpricebase=$_POST["multiprices_base_type_".$i];
$newnpr=(preg_match('/\*/',$_POST["tva_tx_".$i]) ? 1 : 0); $newnpr=(preg_match('/\*/',$_POST["tva_tx_".$i]) ? 1 : 0);
$newvat=str_replace('*','',$_POST["tva_tx_".$i]); $newvat=str_replace('*','',$_POST["tva_tx_".$i]);
$newpsq=GETPOST('psqflag');
$newpsq = empty($newpsq) ? 0 : $newpsq;
break; // We found submited price break; // We found submited price
} }
} }
@ -82,9 +84,11 @@ if ($action == 'update_price' && ! $_POST["cancel"] && ($user->rights->produit->
$newpricebase=$_POST["price_base_type"]; $newpricebase=$_POST["price_base_type"];
$newnpr=(preg_match('/\*/',$_POST["tva_tx"]) ? 1 : 0); $newnpr=(preg_match('/\*/',$_POST["tva_tx"]) ? 1 : 0);
$newvat=str_replace('*','',$_POST["tva_tx"]); $newvat=str_replace('*','',$_POST["tva_tx"]);
$newpsq=GETPOST('psqflag');
$newpsq = empty($newpsq) ? 0 : $newpsq;
} }
if ($object->updatePrice($object->id, $newprice, $newpricebase, $user, $newvat, $newprice_min, $level, $newnpr) > 0) if ($object->updatePrice($object->id, $newprice, $newpricebase, $user, $newvat, $newprice_min, $level, $newnpr, $newpsq) > 0)
{ {
$action = ''; $action = '';
$mesg = '<div class="ok">'.$langs->trans("RecordSaved").'</div>'; $mesg = '<div class="ok">'.$langs->trans("RecordSaved").'</div>';
@ -101,6 +105,92 @@ else if ($action == 'delete' && $user->rights->produit->supprimer)
if ($result < 0) $mesg='<div class="error">'.$object->error.'</div>'; if ($result < 0) $mesg='<div class="error">'.$object->error.'</div>';
} }
/*****************************************************
* Price by quantity
*****************************************************/
$error=0;
if ($action == 'activate_price_by_qty') { // Activating product price by quantity add a new price, specified as by quantity
$result = $object->fetch($id);
$level=GETPOST('level');
$object->updatePrice($object->id, 0, $object->price_base_type, $user, $object->tva_tx, 0, $level, $object->tva_npr, 1);
}
if ($action == 'edit_price_by_qty') { // Edition d'un prix par quantité
$rowid = GETPOST('rowid');
}
if ($action == 'update_price_by_qty') { // Ajout / Mise à jour d'un prix par quantité
$result = $object->fetch($id);
// Récupération des variables
$rowid = GETPOST('rowid');
$priceid=GETPOST('priceid');
$newprice=price2num(GETPOST("price"),'MU');
//$newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management
$quantity=GETPOST('quantity');
$remise_percent=price2num(GETPOST('remise_percent'));
$remise=0; // TODO : allow dicsount by amount when available on documents
if (empty($quantity))
{
$error++;
$mesg='<div class="error">'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Qty")).'</div>';
}
if (empty($newprice))
{
$error++;
$mesg='<div class="error">'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Price")).'</div>';
}
if(!$error) {
// Calcul du prix HT et du prix unitaire
if ($object->price_base_type == 'TTC')
{
$price = price2num($newprice) / (1 + ($object->tva_tx / 100));
}
$price = price2num($newprice,'MU');
$unitPrice = price2num($price/$quantity,'MU');
// Ajout / mise à jour
if($rowid > 0) {
$sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET";
$sql.= " price='".$price."',";
$sql.= " unitprice=".$unitPrice.",";
$sql.= " quantity=".$quantity.",";
$sql.= " remise_percent=".$remise_percent.",";
$sql.= " remise=".$remise;
$sql.= " WHERE rowid = ".GETPOST('rowid');
$result = $db->query($sql);
} else {
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,unitprice,quantity,remise_percent,remise) values (";
$sql.= $priceid.','.$price.','.$unitPrice.','.$quantity.','.$remise_percent.','.$remise.')';
$result = $db->query($sql);
}
}
}
if ($action == 'delete_price_by_qty') {
$rowid = GETPOST('rowid');
$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty";
$sql.= " WHERE rowid = ".GETPOST('rowid');
$result = $db->query($sql);
}
if ($action == 'delete_all_price_by_qty') {
$priceid=GETPOST('priceid');
$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty";
$sql.= " WHERE fk_product_price = ".$priceid;
$result = $db->query($sql);
}
/* /*
* View * View
@ -230,6 +320,77 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES))
print price($object->multiprices_min["$i"]).' '.$langs->trans($object->multiprices_base_type["$i"]); print price($object->multiprices_min["$i"]).' '.$langs->trans($object->multiprices_base_type["$i"]);
} }
print '</td></tr>'; print '</td></tr>';
// Price by quantity
if($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) {
print '<tr><td>'.$langs->trans("PriceByQuantity").' '.$i;
print '</td><td>';
if($object->prices_by_qty[$i] == 1) {
print '<table width="50%" class="noborder">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("PriceByQuantityRange").' '.$i.'</td>';
print '<td align="right">'.$langs->trans("HT").'</td>';
print '<td align="right">'.$langs->trans("UnitPrice").'</td>';
print '<td align="right">'.$langs->trans("Discount").'</td>';
print '<td>&nbsp;</td>';
print '</tr>';
foreach ($object->prices_by_qty_list[$i] as $ii=> $prices) {
if($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->rights->produit->creer || $user->rights->service->creer)) {
print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
print '<input type="hidden" name="action" value="update_price_by_qty">';
print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[$i].'">';
print '<input type="hidden" value="'.$prices['rowid'].'" name="rowid">';
print '<tr class="'.($ii % 2 == 0 ? 'pair':'impair').'">';
print '<td><input size="5" type="text" value="'.$prices['quantity'].'" name="quantity"></td>';
print '<td align="right" colspan="2"><input size="10" type="text" value="'.$prices['price'].'" name="price">&nbsp;'.$object->price_base_type.'</td>';
//print '<td align="right">&nbsp;</td>';
print '<td align="right"><input size="5" type="text" value="'.$prices['remise_percent'].'" name="remise_percent">&nbsp;%</td>';
print '<td align="center"><input type="submit" value="'.$langs->trans("Modify").'" class="button"></td>';
print '</tr>';
print '</form>';
} else {
print '<tr class="'.($ii % 2 == 0 ? 'pair':'impair').'">';
print '<td>'.$prices['quantity'].'</td>';
print '<td align="right">'.price($prices['price']).'</td>';
print '<td align="right">'.price($prices['unitprice']).'</td>';
print '<td align="right">'.price($prices['remise_percent']).' %</td>';
print '<td align="center">';
if(($user->rights->produit->creer || $user->rights->service->creer)) {
print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=edit_price_by_qty&amp;rowid='.$prices["rowid"].'">';
print img_edit().'</a>';
print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=delete_price_by_qty&amp;rowid='.$prices["rowid"].'">';
print img_delete().'</a>';
} else {
print '&nbsp;';
}
print '</td>';
print '</tr>';
}
}
if($action != 'edit_price_by_qty' && ($user->rights->produit->creer || $user->rights->service->creer)) {
print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
print '<input type="hidden" name="action" value="update_price_by_qty">';
print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[$i].'">';
print '<input type="hidden" value="0" name="rowid">';
print '<tr class="'.($ii % 2 == 0 ? 'pair':'impair').'">';
print '<td><input size="5" type="text" value="1" name="quantity"></td>';
print '<td align="right" colspan="2"><input size="10" type="text" value="0" name="price">&nbsp;'.$object->price_base_type.'</td>';
//print '<td align="right">&nbsp;</td>';
print '<td align="right"><input size="5" type="text" value="0" name="remise_percent">&nbsp;%</td>';
print '<td align="center"><input type="submit" value="'.$langs->trans("Add").'" class="button"></td>';
print '</tr>';
print '</form>';
}
print '</table>';
} else {
print $langs->trans("No");
print '&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=activate_price_by_qty&level='.$i.'">('.$langs->trans("Activate").')</a>';
}
print '</td></tr>';
}
} }
} }
} }
@ -261,6 +422,78 @@ else
print price($object->price_min).' '.$langs->trans($object->price_base_type); print price($object->price_min).' '.$langs->trans($object->price_base_type);
} }
print '</td></tr>'; print '</td></tr>';
// Price by quantity
if($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) {
print '<tr><td>'.$langs->trans("PriceByQuantity");
if($object->prices_by_qty[0] == 0) {
print '&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=activate_price_by_qty&level=1">'.$langs->trans("Activate");
}
print '</td><td>';
if($object->prices_by_qty[0] == 1) {
print '<table width="50%" class="noborder">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("PriceByQuantityRange").'</td>';
print '<td align="right">'.$langs->trans("HT").'</td>';
print '<td align="right">'.$langs->trans("UnitPrice").'</td>';
print '<td align="right">'.$langs->trans("Discount").'</td>';
print '<td>&nbsp;</td>';
print '</tr>';
foreach ($object->prices_by_qty_list[0] as $ii=> $prices) {
if($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->rights->produit->creer || $user->rights->service->creer)) {
print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
print '<input type="hidden" name="action" value="update_price_by_qty">';
print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[0].'">';
print '<input type="hidden" value="'.$prices['rowid'].'" name="rowid">';
print '<tr class="'.($ii % 2 == 0 ? 'pair':'impair').'">';
print '<td><input size="5" type="text" value="'.$prices['quantity'].'" name="quantity"></td>';
print '<td align="right" colspan="2"><input size="10" type="text" value="'.$prices['price'].'" name="price">&nbsp;'.$object->price_base_type.'</td>';
//print '<td align="right">&nbsp;</td>';
print '<td align="right"><input size="5" type="text" value="'.$prices['remise_percent'].'" name="remise_percent">&nbsp;%</td>';
print '<td align="center"><input type="submit" value="'.$langs->trans("Modify").'" class="button"></td>';
print '</tr>';
print '</form>';
} else {
print '<tr class="'.($ii % 2 == 0 ? 'pair':'impair').'">';
print '<td>'.$prices['quantity'].'</td>';
print '<td align="right">'.price($prices['price']).'</td>';
print '<td align="right">'.price($prices['unitprice']).'</td>';
print '<td align="right">'.price($prices['remise_percent']).' %</td>';
print '<td align="center">';
if(($user->rights->produit->creer || $user->rights->service->creer)) {
print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=edit_price_by_qty&amp;rowid='.$prices["rowid"].'">';
print img_edit().'</a>';
print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=delete_price_by_qty&amp;rowid='.$prices["rowid"].'">';
print img_delete().'</a>';
} else {
print '&nbsp;';
}
print '</td>';
print '</tr>';
}
}
if($action != 'edit_price_by_qty') {
print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
print '<input type="hidden" name="action" value="update_price_by_qty">';
print '<input type="hidden" name="priceid" value="'.$object->prices_by_qty_id[0].'">';
print '<input type="hidden" value="0" name="rowid">';
print '<tr class="'.($ii % 2 == 0 ? 'pair':'impair').'">';
print '<td><input size="5" type="text" value="1" name="quantity"></td>';
print '<td align="right" colspan="2"><input size="10" type="text" value="0" name="price">&nbsp;'.$object->price_base_type.'</td>';
//print '<td align="right">&nbsp;</td>';
print '<td align="right"><input size="5" type="text" value="0" name="remise_percent">&nbsp;%</td>';
print '<td align="center"><input type="submit" value="'.$langs->trans("Add").'" class="button"></td>';
print '</tr>';
print '</form>';
}
print '</table>';
} else {
print $langs->trans("No");
}
print '</td></tr>';
}
} }
// Status (to sell) // Status (to sell)
@ -426,7 +659,7 @@ if ($action == 'edit_price' && ($user->rights->produit->creer || $user->rights->
// Liste des evolutions du prix // Liste des evolutions du prix
$sql = "SELECT p.rowid, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.recuperableonly,"; $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,"; $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, u.rowid as user_id, u.login";
$sql.= " FROM ".MAIN_DB_PREFIX."product_price as p,"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price as p,";
$sql.= " ".MAIN_DB_PREFIX."user as u"; $sql.= " ".MAIN_DB_PREFIX."user as u";
@ -464,7 +697,11 @@ if ($result)
if (! empty($conf->global->PRODUIT_MULTIPRICES)) if (! empty($conf->global->PRODUIT_MULTIPRICES))
{ {
print '<td>'.$langs->trans("MultiPriceLevelsName").'</td>'; print '<td align="center">'.$langs->trans("MultiPriceLevelsName").'</td>';
}
if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY))
{
print '<td align="center">'.$langs->trans("Type").'</td>';
} }
print '<td align="center">'.$langs->trans("PriceBase").'</td>'; print '<td align="center">'.$langs->trans("PriceBase").'</td>';
@ -492,6 +729,12 @@ if ($result)
{ {
print '<td align="center">'.$objp->price_level."</td>"; print '<td align="center">'.$objp->price_level."</td>";
} }
// Price by quantity
if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY))
{
$type = ($objp->price_by_qty == 1) ? 'PriceByQuantity' : 'Standard';
print '<td align="center">'.$langs->trans($type)."</td>";
}
print '<td align="center">'.$langs->trans($objp->price_base_type)."</td>"; print '<td align="center">'.$langs->trans($objp->price_base_type)."</td>";
print '<td align="right">'.vatrate($objp->tva_tx,true,$objp->recuperableonly)."</td>"; print '<td align="right">'.vatrate($objp->tva_tx,true,$objp->recuperableonly)."</td>";