diff --git a/htdocs/conf/conf.class.php b/htdocs/conf/conf.class.php
index d41679740ef..cc4ddad14c7 100644
--- a/htdocs/conf/conf.class.php
+++ b/htdocs/conf/conf.class.php
@@ -472,11 +472,11 @@ class Conf
$this->format_date_short_java="dd/MM/yyyy";
- // Format montant affichés
- if (! isset($this->global->MAIN_MAX_DECIMALS_SHOWN))
- {
- $this->global->MAIN_MAX_DECIMALS_SHOWN=5;
- }
+ // Limites decimales
+ if (! isset($this->global->MAIN_MAX_DECIMALS_UNIT)) $this->global->MAIN_MAX_DECIMALS_UNIT=5;
+ if (! isset($this->global->MAIN_MAX_DECIMALS_TTC)) $this->global->MAIN_MAX_DECIMALS_TTC=2;
+ if (! isset($this->global->MAIN_MAX_DECIMALS_SHOWN)) $this->global->MAIN_MAX_DECIMALS_SHOWN=8;
+
/* \todo Ajouter une option Gestion de la TVA dans le module compta qui permet de désactiver la fonction TVA
* (pour particuliers ou libéraux en franchise)
diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang
index ecef7dad84d..3f039f2eb31 100644
--- a/htdocs/langs/en_US/bills.lang
+++ b/htdocs/langs/en_US/bills.lang
@@ -78,6 +78,7 @@ EnterPaymentDueToCustomer=Make payment due to customer
VAT=VAT
VATRate=VAT Rate
Amount=Amount
+PriceBase=Price base
TotalTTCToYourCredit=Total TTC to your credit
BillStatus=Invoice status
BillStatusDraft=Draft (needs to be validated)
diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
index 1592e113768..eb274c03dc8 100644
--- a/htdocs/langs/en_US/main.lang
+++ b/htdocs/langs/en_US/main.lang
@@ -52,6 +52,7 @@ InformationToHelpDiagnose=This is information that can help to diagnose
MoreInformation=More information
NotePublic=Note (public)
NotePrivate=Note (private)
+PrecisionUnitIsLimitedToXDecimals=Dolibarr was setup to limit precision of unit prices to %s decimals.
yes=yes
Yes=Yes
no=no
diff --git a/htdocs/langs/fr_FR/bills.lang b/htdocs/langs/fr_FR/bills.lang
index af63e94ffd8..cca0561be94 100644
--- a/htdocs/langs/fr_FR/bills.lang
+++ b/htdocs/langs/fr_FR/bills.lang
@@ -78,6 +78,7 @@ EnterPaymentDueToCustomer=R
VAT=TVA
VATRate=Taux TVA
Amount=Montant
+PriceBase=Base du prix
TotalTTCToYourCredit=Total TTC à votre crédit
BillStatus=État de la facture
BillStatusDraft=Brouillon (à valider)
diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang
index f76516b9d30..8ea10dd8f28 100644
--- a/htdocs/langs/fr_FR/main.lang
+++ b/htdocs/langs/fr_FR/main.lang
@@ -52,6 +52,7 @@ InformationToHelpDiagnose=Voici les informations qui pourront aider au diagnosti
MoreInformation=Plus d'information
NotePublic=Note (publique)
NotePrivate=Note (privée)
+PrecisionUnitIsLimitedToXDecimals=Dolibarr a été configuré pour limiter la précision des prix unitaires à %s décimals.
yes=oui
Yes=Oui
no=non
diff --git a/htdocs/lib/functions.inc.php b/htdocs/lib/functions.inc.php
index c762dfa9969..31e3c7ffbc8 100644
--- a/htdocs/lib/functions.inc.php
+++ b/htdocs/lib/functions.inc.php
@@ -1896,12 +1896,12 @@ function print_fleche_navigation($page,$file,$options='',$nextpage)
/**
-* \brief Fonction qui retourne un montant monétaire formaté
+* \brief Fonction qui retourne un montant monétaire formaté pour visualisation
* \remarks Fonction utilisée dans les pdf et les pages html
* \param amount Montant a formater
* \param html Formatage html ou pas (0 par defaut)
* \param outlangs Objet langs pour formatage
-* \param trunc 1=Tronque affichage si trop de décimales
+* \param trunc 1=Tronque affichage si trop de décimales,0=Force le non troncage
* \return string Chaine avec montant formaté
* \seealso price2num Fonction inverse de price
*/
@@ -1919,12 +1919,13 @@ function price($amount, $html=0, $outlangs='', $trunc=1)
if ($outlangs->trans("SeparatorThousand")!= "SeparatorThousand") $thousand=$outlangs->trans("SeparatorThousand");
//print "dec=".$dec." thousand=".$thousand;
- //print "xx".$amount."-";
+ //print "amount=".$amount."-";
$amount = ereg_replace(',','.',$amount);
//print $amount."-";
$datas = split("\.",$amount);
$decpart = $datas[1];
- //print $datas[1]."
";
+ $decpart = eregi_replace('0+$','',$decpart); // Supprime les 0 de fin de partie décimale
+ //print "decpart=".$decpart."
";
// On pose par defaut 2 decimales
$nbdecimal = 2;
@@ -1953,16 +1954,35 @@ function price($amount, $html=0, $outlangs='', $trunc=1)
}
/**
- \brief Fonction qui retourne un numérique depuis un montant formaté
- \remarks Fonction à appeler sur montants saisi avant un insert
- \param amount montant a formater
- \seealso price Fonction inverse de price2num
+ \brief Fonction qui retourne un numérique conforme PHP et SQL, depuis un montant au
+ format utilisateur.
+ \remarks Fonction à appeler sur montants saisis avant un insert en base
+ \param amount Montant a formater
+ \param rounding 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT)
+ 'MT'=Round to Max with Tax (MAIN_MAX_DECIMALS_TTC)
+ 'MS'=Round to Max Shown (MAIN_MAX_DECIMALS_SHOWN)
+ ''=No rounding
+ \return string Montant au format numérique PHP et SQL (Exemple: '99.99999')
+ \seealso price Fonction inverse de price2num
*/
-function price2num($amount)
+function price2num($amount,$rounding='')
{
- $amount=ereg_replace(',','.',$amount);
- $amount=ereg_replace(' ','',$amount);
- return $amount;
+ global $conf;
+
+ // Round PHP function does not allow number like '1,234.5'.
+ // Numbers must be '1234.5'
+ $amount=ereg_replace(',','.',$amount);
+ $amount=ereg_replace(' ','',$amount);
+ if ($rounding)
+ {
+ if ($rounding == 'MU') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_UNIT);
+ elseif ($rounding == 'MT') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_TTC);
+ elseif ($rounding == 'MS') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_SHOWN);
+ else $amount='ErrorBadParameterProvidedToFunction';
+ $amount=ereg_replace(',','.',$amount);
+ $amount=ereg_replace(' ','',$amount);
+ }
+ return $amount;
}
diff --git a/htdocs/lib/price.lib.php b/htdocs/lib/price.lib.php
index dbafff80f06..c4a834e3075 100644
--- a/htdocs/lib/price.lib.php
+++ b/htdocs/lib/price.lib.php
@@ -23,12 +23,13 @@
/**
\file htdocs/lib/price.lib.php
\brief Librairie contenant les fonctions pour calculer un prix.
- \author Rodolphe Quiedeville.
+ \author Rodolphe Quiedeville.
\version $Revision$
Ensemble des fonctions permettant de calculer un prix.
*/
+
/**
\brief Permet de calculer les parts total HT, TVA et TTC d'une ligne de
facture, propale, commande ou autre depuis:
diff --git a/htdocs/product.class.php b/htdocs/product.class.php
index 2f5f2ac369e..95eacf78358 100644
--- a/htdocs/product.class.php
+++ b/htdocs/product.class.php
@@ -130,18 +130,7 @@ class Product
return 1;
}
}
- /**
- * \brief Definit le prix de vente
- * \return void
- */
- function SetSellPrice($price, $base_type='HT')
- {
- $price = ereg_replace(" ","", $price);
- $price = ereg_replace(",",".", $price);
- $this->price = $price;
- $this->price_base_type = $base_type;
- }
/**
\brief Insère le produit en base
\param user Utilisateur qui effectue l'insertion
@@ -574,130 +563,70 @@ class Product
- /**
- * \brief Ajoute un changement de prix en base dans l'historique des prix
- * \param user utilisateur qui modifie le prix
- */
- function _log_price($user)
- {
- // MultiPrix : si activé, on gère tout ici, même le prix standard
- global $conf;
- if($conf->global->PRODUIT_MULTIPRICES == 1)
- {
- $queryError = false;
- for($i=2;$i<=$conf->global->PRODUIT_MULTIPRICES_LIMIT;$i++)
- {
- if($this->multiprices["$i"] != "")
- {
- if ($this->multiprices_base_type["$i"] == 'TTC')
- {
- $price_ttc = $this->multiprices["$i"];
- $this->multiprices["$i"] = $this->multiprices["$i"] / (1 + ($this->tva_tx / 100));
- }
- else
- {
- $price_ttc = $this->multiprices["$i"] * (1 + ($this->tva_tx / 100));
- }
+ /**
+ * \brief Ajoute un changement de prix en base dans l'historique des prix
+ * \param user Objet utilisateur qui modifie le prix
+ * \return int <0 si KO, >0 si OK
+ */
+ function _log_price($user)
+ {
+ // MultiPrix : si activé, on gère tout ici, même le prix standard
+ global $conf;
- // On supprimme ligne existante au cas ou
- $sql_multiprix = "DELETE FROM ".MAIN_DB_PREFIX."product_price ";
- $sql_multiprix .= "WHERE date_price = now()";
- $sql_multiprix .= " and fk_product = ".$this->id;
- $sql_multiprix .= " and fk_user_author = ".$user->id;
- $sql_multiprix .= " and price = ".price2num($this->multiprices["$i"]);
+ if ($conf->global->PRODUIT_MULTIPRICES)
+ {
+ $queryError = false;
+ for($i=2;$i<=$conf->global->PRODUIT_MULTIPRICES_LIMIT;$i++)
+ {
+ if($this->multiprices["$i"] != "")
+ {
+ // On ajoute nouveau tarif
+ $sql_multiprix = "INSERT INTO ".MAIN_DB_PREFIX."product_price(date_price,fk_product,fk_user_author,price_level,price,price_ttc,price_base_type,tva_tx) ";
+ $sql_multiprix .= " VALUES(now(),".$this->id.",".$user->id.",".$i.",".price2num($this->multiprices["$i"]).",'".price2num($this->multiprices_ttc["$i"])."','".$this->multiprices_base_type["$i"]."',".$this->tva_tx;
+ $sql_multiprix .= ")";
+ if (! $this->db->query($sql_multiprix) )
+ {
+ $queryError = true;
+ }
+ }
+ }
+ if (strlen(trim($this->price)) > 0 )
+ {
+ // On ajoute nouveau tarif
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price(date_price,fk_product,fk_user_author,price,price_ttc,price_base_type,envente,tva_tx) ";
+ $sql .= " VALUES(now(),".$this->id.",".$user->id.",".$this->price.",".$this->price_ttc.",'".$this->price_base_type."',".$this->status.",".$this->tva_tx;
+ $sql .= ")";
+ if (! $this->db->query($sql) )
+ $queryError = true;
+ }
+ if($queryError)
+ {
+ dolibarr_print_error($this->db);
+ return 0;
+ }
+ else
+ return 1;
+ }
+ else
+ {
+ // On ajoute nouveau tarif
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price(date_price,fk_product,fk_user_author,price,price_ttc,price_base_type,envente,tva_tx) ";
+ $sql .= " VALUES(now(),".$this->id.",".$user->id.",".$this->price.",".$this->price_ttc.",'".$this->price_base_type."',".$this->status.",".$this->tva_tx;
+ $sql .= ")";
- $this->db->query($sql_multiprix);
-
- // On ajoute nouveau tarif
- $sql_multiprix = "INSERT INTO ".MAIN_DB_PREFIX."product_price(date_price,fk_product,fk_user_author,price_level,price,price_ttc,price_base_type,tva_tx) ";
- $sql_multiprix .= " VALUES(now(),".$this->id.",".$user->id.",".$i.",".price2num($this->multiprices["$i"]).",'".$price_ttc."','".$this->multiprices_base_type["$i"]."',".$this->tva_tx;
- $sql_multiprix .= ")";
- if (! $this->db->query($sql_multiprix) )
- {
- $queryError = true;
- }
- }
- }
- if (strlen(trim($this->price)) > 0 )
- {
- if ($this->price_base_type == 'TTC')
- {
- $price_ttc = $this->price;
- $price = $this->price / (1 + ($this->tva_tx / 100));
- }
- else
- {
- $price = $this->price;
- $price_ttc = $this->price * (1 + ($this->tva_tx / 100));
- }
-
- // On supprimme ligne existante au cas ou
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price ";
- $sql .= "WHERE date_price = now()";
- $sql .= " and fk_product = ".$this->id;
- $sql .= " and fk_user_author = ".$user->id;
- $sql .= " and price = ".price2num($price);
- $sql .= " and envente = ".$this->status;
- $sql .= " and tva_tx = ".$this->tva_tx;
-
- $this->db->query($sql);
-
- // On ajoute nouveau tarif
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price(date_price,fk_product,fk_user_author,price,price_ttc,price_base_type,envente,tva_tx) ";
- $sql .= " VALUES(now(),".$this->id.",".$user->id.",".price2num($price).",'".$price_ttc."','".$this->price_base_type."',".$this->status.",".$this->tva_tx;
- $sql .= ")";
- if (! $this->db->query($sql) )
- $queryError = true;
- }
- if($queryError)
- {
- dolibarr_print_error($this->db);
- return 0;
- }
- else
- return 1;
- }
- else
- {
- if ($this->price_base_type == 'TTC')
- {
- $price_ttc = $this->price;
- $price = $this->price / (1 + ($this->tva_tx / 100));
- }
- else
- {
- $price = $this->price;
- $price_ttc = $this->price * (1 + ($this->tva_tx / 100));
- }
-
- // On supprimme ligne existante au cas ou
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price ";
- $sql .= "WHERE date_price = now()";
- $sql .= " and fk_product = ".$this->id;
- $sql .= " and fk_user_author = ".$user->id;
- $sql .= " and price = ".price2num($this->price);
- $sql .= " and envente = ".$this->status;
- $sql .= " and tva_tx = ".$this->tva_tx;
-
- $this->db->query($sql);
-
- // On ajoute nouveau tarif
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price(date_price,fk_product,fk_user_author,price,price_ttc,price_base_type,envente,tva_tx) ";
- $sql .= " VALUES(now(),".$this->id.",".$user->id.",".price2num($price).",'".$price_ttc."','".$this->price_base_type."',".$this->status.",".$this->tva_tx;
- $sql .= ")";
-
- if ($this->db->query($sql) )
- {
- return 1;
- }
- else
- {
- dolibarr_print_error($this->db);
- return 0;
- }
- }
-
- }
+ dolibarr_syslog("Product::_log_price sql=".$sql);
+ $resql=$this->db->query($sql);
+ if ($resql)
+ {
+ return 1;
+ }
+ else
+ {
+ dolibarr_print_error($this->db);
+ return -1;
+ }
+ }
+ }
/**
@@ -869,57 +798,70 @@ class Product
}
- /**
- \brief Modifie le prix d'un produit/service
- \param id id du produit/service à modifier
- \param user utilisateur qui modifie le prix
- */
- function update_price($id, $user)
- {
- //multiprix
- global $conf;
+ /**
+ \brief Modifie le prix d'un produit/service
+ \param id Id du produit/service à modifier
+ \param newprice Nouveau prix
+ \param newpricebase HT ou TTC
+ \param user Objet utilisateur qui modifie le prix
+ */
+ function update_price($id, $newprice, $newpricebase, $user)
+ {
+ //multiprix
+ global $conf,$langs;
+ dolibarr_syslog("Product::update_price id=".$id." newprice=".$newprice." newpricebase=".$newpricebase);
- if (strlen(trim($this->price)) > 0 )
- {
- if ($this->price_base_type == 'TTC')
- {
- $price_ttc = $this->price;
- $price = $this->price / (1 + ($this->tva_tx / 100));
- }
- else
- {
- $price = $this->price;
- $price_ttc = $this->price * (1 + ($this->tva_tx / 100));
- }
-
- $sql = "UPDATE ".MAIN_DB_PREFIX."product ";
- $sql .= " SET price = " . price2num($price);
- $sql .= " , price_base_type='".$this->price_base_type."'";
- $sql .= " , price_ttc='".$price_ttc."'";
- $sql .= " WHERE rowid = " . $id;
+ if ($newprice)
+ {
+ if ($newpricebase == 'TTC')
+ {
+ $price_ttc = price2num($newprice,'MU');
+ $price = price2num($newprice) / (1 + ($this->tva_tx / 100));
+ $price = price2num($price,'MU');
+ }
+ else
+ {
+ $price = price2num($newprice,'MU');
+ $price_ttc = price2num($newprice) * (1 + ($this->tva_tx / 100));
+ $price_ttc = price2num($price_ttc,'MU');
+ }
+
+ // Ne pas mettre de quote sur le numériques decimaux.
+ // Ceci provoque des sotckage avec arrondis en base au lieu des valeurs exactes.
+ $sql = "UPDATE ".MAIN_DB_PREFIX."product ";
+ $sql .= " SET price=".$price."";
+ $sql .= " , price_base_type='".$newpricebase."'";
+ $sql .= " , price_ttc=".$price_ttc."";
+ $sql .= " WHERE rowid = " . $id;
- if ( $this->db->query($sql) )
- {
- $this->_log_price($user);
- return 1;
- }
- else
- {
- dolibarr_print_error($this->db);
- return -1;
- }
- }
- else if(($conf->global->PRODUIT_MULTIPRICES == 1) && (count($this->multiprices) > 0))
- {
- $this->_log_price($user);
- return 1;
- }
- else
- {
- $this->error = "Prix saisi invalide.";
- return -2;
- }
- }
+ dolibarr_syslog("Product::update_price sql=".$sql);
+ $resql=$this->db->query($sql);
+ if ($resql)
+ {
+ $this->price = $price;
+ $this->price_ttc = $price_ttc;
+ $this->price_base_type = $newpricebase;
+
+ $this->_log_price($user);
+ return 1;
+ }
+ else
+ {
+ dolibarr_print_error($this->db);
+ return -1;
+ }
+ }
+ else if(($conf->global->PRODUIT_MULTIPRICES) && (count($this->multiprices) > 0))
+ {
+ $this->_log_price($user);
+ return 1;
+ }
+ else
+ {
+ $this->error = $langs->trans("ErrorBadParameter");
+ return -2;
+ }
+ }
/**
@@ -957,9 +899,9 @@ class Product
$this->id = $result["rowid"];
$this->ref = $result["ref"];
- $this->libelle = stripslashes($result["label"]);
- $this->description = stripslashes($result["description"]);
- $this->note = stripslashes($result["note"]);
+ $this->libelle = $result["label"];
+ $this->description = $result["description"];
+ $this->note = $result["note"];
$this->price = $result["price"];
$this->price_ttc = $result["price_ttc"];
$this->price_base_type = $result["price_base_type"];
@@ -987,7 +929,7 @@ class Product
if( $conf->global->MAIN_MULTILANGS) $this->getMultiLangs();
// multiprix
- if($conf->global->PRODUIT_MULTIPRICES == 1)
+ if ($conf->global->PRODUIT_MULTIPRICES)
{
if ($ref)
{
diff --git a/htdocs/product/price.php b/htdocs/product/price.php
index e786d1d1cc4..8254749990b 100644
--- a/htdocs/product/price.php
+++ b/htdocs/product/price.php
@@ -42,7 +42,7 @@ $user->getrights('produit');
if (!$user->rights->produit->lire)
accessforbidden();
-$html = new Form($db);
+
/*
* Actions
@@ -51,48 +51,49 @@ $html = new Form($db);
if ($_POST["action"] == 'update_price' &&
$_POST["cancel"] <> $langs->trans("Cancel") && $user->rights->produit->creer)
{
- $product = new Product($db);
-
- $result = $product->fetch($_GET["id"]);
+ $product = new Product($db);
- $product->SetSellprice($_POST["price"], $_POST["price_base_type"]);
+ $result = $product->fetch($_GET["id"]);
- // MultiPrix
- if($conf->global->PRODUIT_MULTIPRICES == 1)
- {
- for($i=2;$i<=$conf->global->PRODUIT_MULTIPRICES_LIMIT;$i++)
- {
- if($_POST["price_".$i])
- {
- $price = ereg_replace(" ","", $_POST["price_".$i]);
- $price = ereg_replace(",",".", $price);
- $product->multiprices["$i"] = $price;
- $product->multiprices_base_type["$i"] = $_POST["multiprices_base_type_".$i];
- }
- else
- {
- $product->multiprices["$i"] = "";
- }
- }
- }
-
- if ( $product->update_price($product->id, $user) > 0 )
- {
- $_GET["action"] = '';
- $mesg = 'Fiche mise à jour';
- }
- else
- {
- $_GET["action"] = 'edit_price';
- $mesg = 'Fiche non mise à jour !' . "
" . $product->mesg_error;
- }
+ $newprice=price2num($_POST["price"],'MU');
+ $newpricebase=$_POST["price_base_type"];
+
+ // MultiPrix
+ if($conf->global->PRODUIT_MULTIPRICES)
+ {
+ for($i=2;$i<=$conf->global->PRODUIT_MULTIPRICES_LIMIT;$i++)
+ {
+ if($_POST["price_".$i])
+ {
+ $price = ereg_replace(" ","", $_POST["price_".$i]);
+ $price = ereg_replace(",",".", $price);
+ $product->multiprices["$i"] = $price;
+ $product->multiprices_base_type["$i"] = $_POST["multiprices_base_type_".$i];
+ }
+ else
+ {
+ $product->multiprices["$i"] = "";
+ }
+ }
+ }
+
+ if ($product->update_price($product->id, $newprice, $newpricebase, $user) > 0)
+ {
+ $_GET["action"] = '';
+ $mesg = $langs->trans("RecordSaved");
+ }
+ else
+ {
+ $_GET["action"] = 'edit_price';
+ $mesg = '