Fix: Pb with floating operations

This commit is contained in:
Laurent Destailleur
2008-08-08 22:12:27 +00:00
parent 74b1f2c4b1
commit 1a911fc38a
11 changed files with 123 additions and 85 deletions

View File

@@ -81,7 +81,7 @@ if (isset($_GET["action"]) && $_GET["action"] == 'del_bookmark')
/*
* Affichage page
* View
*/
$html = new Form($db);

View File

@@ -896,7 +896,7 @@ if ($_GET['propalid'] > 0)
// Remise dispo de type non avoir
$filter='fk_facture_source IS NULL';
print '<br>';
print $html->form_remise_dispo($_SERVER["PHP_SELF"].'?propalid='.$propal->id,0,'remise_id',$societe->id,$absolute_discount,$filter);
$html->form_remise_dispo($_SERVER["PHP_SELF"].'?propalid='.$propal->id,0,'remise_id',$societe->id,$absolute_discount,$filter);
}
}
if ($absolute_creditnote)

View File

@@ -19,10 +19,10 @@
*/
/**
\file htdocs/comm/remx.php
\ingroup commercial, invoice
\brief Onglet de d<>finition des avoirs
\version $Id$
* \file htdocs/comm/remx.php
* \ingroup commercial, invoice
* \brief Onglet de d<>finition des avoirs
* \version $Id$
*/
require_once("./pre.inc.php");
@@ -95,7 +95,7 @@ if ($_GET["action"] == 'remove')
/*
* Affichage fiche des remises fixes
* View
*/
$form=new Form($db);

View File

@@ -1204,7 +1204,7 @@ else
// Remise dispo de type non avoir
$filter='fk_facture_source IS NULL';
print '<br>';
print $html->form_remise_dispo($_SERVER["PHP_SELF"].'?id='.$commande->id,0,'remise_id',$soc->id,$absolute_discount,$filter);
$html->form_remise_dispo($_SERVER["PHP_SELF"].'?id='.$commande->id,0,'remise_id',$soc->id,$absolute_discount,$filter);
}
}
if ($absolute_creditnote)

View File

@@ -191,7 +191,7 @@ if ($_GET["id"] > 0)
// Remise dispo de type non avoir
$filter='fk_facture_source IS NULL';
print '<br>';
print $html->form_remise_dispo($_SERVER["PHP_SELF"].'?id='.$commande->id,0,'remise_id',$soc->id,$absolute_discount,$filter);
$html->form_remise_dispo($_SERVER["PHP_SELF"].'?id='.$commande->id,0,'remise_id',$soc->id,$absolute_discount,$filter);
}
}
if ($absolute_creditnote)

View File

@@ -1809,15 +1809,21 @@ else
$soc = new Societe($db, $fac->socid);
$soc->fetch($fac->socid);
$absolute_discount=$soc->getAvailableDiscounts('','fk_facture_source IS NULL');
$absolute_creditnote=$soc->getAvailableDiscounts('','fk_facture_source IS NOT NULL');
$totalpaye = $fac->getSommePaiement();
$totalavoir = $fac->getSommeCreditNote();
$resteapayer = $fac->total_ttc - $totalpaye - $totalavoir;
// We cal also use bcadd to avoid pb with floating points
// For example print 239.2 - 229.3 - 9.9; does not return 0.
//$resteapayer=bcadd($fac->total_ttc,$totalpaye,$conf->global->MAIN_MAX_DECIMALS_TOT);
//$resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT);
$resteapayer = price2num($fac->total_ttc - $totalpaye - $totalavoir,'MT');
if ($fac->paye) $resteapayer=0;
$resteapayeraffiche=$resteapayer;
$absolute_discount=$soc->getAvailableDiscounts('','fk_facture_source IS NULL');
$absolute_creditnote=$soc->getAvailableDiscounts('','fk_facture_source IS NOT NULL');
$author = new User($db);
if ($fac->user_author)
{
@@ -2080,7 +2086,7 @@ else
if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_client);
else print $langs->trans("CompanyHasNoRelativeDiscount");
print '. ';
if ($absolute_discount)
if ($absolute_discount > 0)
{
if ($fac->statut > 0 || $fac->type == 2)
{
@@ -2091,10 +2097,10 @@ else
// Remise dispo de type non avoir
$filter='fk_facture_source IS NULL';
print '<br>';
print $html->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$fac->id,0,'remise_id',$soc->id,$absolute_discount,$filter);
$html->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$fac->id,0,'remise_id',$soc->id,$absolute_discount,$filter,$resteapayer);
}
}
if ($absolute_creditnote)
if ($absolute_creditnote > 0)
{
// If validated, we show link "add credit note to payment"
if ($fac->statut != 1 || $fac->type == 2)
@@ -2106,7 +2112,7 @@ else
// Remise dispo de type avoir
$filter='fk_facture_source IS NOT NULL';
if (! $absolute_discount) print '<br>';
print $html->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$fac->id,0,'remise_id_for_payment',$soc->id,$absolute_creditnote,$filter);
$html->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$fac->id,0,'remise_id_for_payment',$soc->id,$absolute_creditnote,$filter,$resteapayer);
}
}
if (! $absolute_discount && ! $absolute_creditnote) print $langs->trans("CompanyHasNoAbsoluteDiscount").'.';
@@ -2143,7 +2149,7 @@ else
print '<td>'.($fac->type == 2 ? $langs->trans("PaymentsBack") : $langs->trans('Payments')).'</td>';
print '<td>'.$langs->trans('Type').'</td>';
print '<td align="right">'.$langs->trans('Amount').'</td>';
print '<td>&nbsp;</td>';
print '<td width="18">&nbsp;</td>';
print '</tr>';
if ($fac->type != 2)
@@ -2158,16 +2164,16 @@ else
print dolibarr_print_date($objp->dp,'day').'</a></td>';
print '<td>'.$objp->paiement_type.' '.$objp->num_paiement.'</td>';
print '<td align="right">'.price($objp->amount).'</td>';
print '<td>'.$langs->trans('Currency'.$conf->monnaie).'</td>';
print '<td>&nbsp;</td>';
print '</tr>';
$i++;
}
// Already payed
print '<tr><td colspan="2" align="right">'.$langs->trans('AlreadyPayed').' :</td><td align="right"><b>'.price($totalpaye).'</b></td><td nowrap="nowrap">'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '<tr><td colspan="2" align="right">'.$langs->trans('AlreadyPayed').' :</td><td align="right"><b>'.price($totalpaye).'</b></td><td>&nbsp;</td></tr>';
// Billed
print '<tr><td colspan="2" align="right">'.$langs->trans("Billed").' :</td><td align="right" style="border: 1px solid;">'.price($fac->total_ttc).'</td><td>'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '<tr><td colspan="2" align="right">'.$langs->trans("Billed").' :</td><td align="right" style="border: 1px solid;">'.price($fac->total_ttc).'</td><td>&nbsp;</td></tr>';
$resteapayeraffiche=$resteapayer;
// Loop on each credit note applied
@@ -2189,7 +2195,7 @@ else
print $invoice->getNomUrl(0);
print ' :</td>';
print '<td align="right" style="border: 1px solid;">'.price($obj->amount_ttc).'</td>';
print '<td nowrap="nowrap">'.$langs->trans('Currency'.$conf->monnaie);
print '<td align="right">';
print '<a href="'.$_SERVER["PHP_SELF"].'?facid='.$fac->id.'&action=unlinkdiscount&discountid='.$obj->rowid.'">'.img_delete().'</a>';
print '</td></tr>';
$i++;
@@ -2205,7 +2211,7 @@ else
{
print '<tr><td colspan="2" align="right" nowrap="1">';
print $html->textwithhelp($langs->trans("Escompte").':',$langs->trans("HelpEscompte"),-1);
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>&nbsp;</td></tr>';
$resteapayeraffiche=0;
}
// Pay<61> partiellement ou Abandon 'badcustomer'
@@ -2213,7 +2219,7 @@ else
{
print '<tr><td colspan="2" align="right" nowrap="1">';
print $html->textwithhelp($langs->trans("Abandoned").':',$langs->trans("HelpAbandonBadCustomer"),-1);
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>&nbsp;</td></tr>';
//$resteapayeraffiche=0;
}
// Pay<61> partiellement ou Abandon 'product_returned'
@@ -2221,7 +2227,7 @@ else
{
print '<tr><td colspan="2" align="right" nowrap="1">';
print $html->textwithhelp($langs->trans("ProductReturned").':',$langs->trans("HelpAbandonProductReturned"),-1);
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>&nbsp;</td></tr>';
$resteapayeraffiche=0;
}
// Pay<61> partiellement ou Abandon 'abandon'
@@ -2231,7 +2237,7 @@ else
$text=$langs->trans("HelpAbandonOther");
if ($fac->close_note) $text.='<br><br><b>'.$langs->trans("Reason").'</b>:'.$fac->close_note;
print $html->textwithhelp($langs->trans("Abandoned").':',$text,-1);
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '</td><td align="right">'.price($fac->total_ttc - $totalpaye).'</td><td>&nbsp;</td></tr>';
$resteapayeraffiche=0;
}
print '<tr><td colspan="2" align="right">';
@@ -2239,13 +2245,13 @@ else
else print $langs->trans('ExcessReceived');
print ' :</td>';
print '<td align="right" style="border: 1px solid;" bgcolor="#f0f0f0"><b>'.price($resteapayeraffiche).'</b></td>';
print '<td wrap="nowrap">'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '<td wrap="nowrap">&nbsp;</td></tr>';
}
else
{
// Solde avoir
print '<tr><td colspan="2" align="right">'.$langs->trans('TotalTTCToYourCredit').' :</td>';
print '<td align="right" style="border: 1px solid;" bgcolor="#f0f0f0"><b>'.price(abs($fac->total_ttc)).'</b></td><td>'.$langs->trans('Currency'.$conf->monnaie).'</td></tr>';
print '<td align="right" style="border: 1px solid;" bgcolor="#f0f0f0"><b>'.price(abs($fac->total_ttc)).'</b></td><td>&nbsp;</td></tr>';
}
print '</table>';
$db->free($result);

View File

@@ -396,7 +396,7 @@ if ($_GET['action'] == 'create' || $_POST['action'] == 'confirm_paiement' || $_P
print '</td>';
// Reste a payer
print '<td align="right">'.price($objp->total_ttc - $objp->am - $creditnote).'</td>';
print '<td align="right">'.price(price2num($objp->total_ttc - $objp->am - $creditnote,'MT')).'</td>';
// Montant
print '<td align="right">';
@@ -430,7 +430,7 @@ if ($_GET['action'] == 'create' || $_POST['action'] == 'confirm_paiement' || $_P
print '<td align="right"><b>'.price($totalrecu);
if ($totalrecucreditnote) print '+'.price($totalrecucreditnote);
print '</b></td>';
print '<td align="right"><b>'.price($total_ttc - $totalrecu - $totalrecucreditnote).'</b></td>';
print '<td align="right"><b>'.price(price2num($total_ttc - $totalrecu - $totalrecucreditnote,'MT')).'</b></td>';
print '<td align="center">&nbsp;</td>';
print '<td align="center">&nbsp;</td>';
print "</tr>\n";

View File

@@ -18,18 +18,17 @@
*/
/**
\file htdocs/discount.class.php
\ingroup propal facture commande
\brief Fichier de la classe de gestion des remises
\version $Id$
* \file htdocs/discount.class.php
* \ingroup propal facture commande
* \brief Fichier de la classe de gestion des remises
* \version $Id$
*/
/**
\class DiscountAbsolute
\brief Classe permettant la gestion des remises fixes
* \class DiscountAbsolute
* \brief Classe permettant la gestion des remises fixes
*/
class DiscountAbsolute
{
var $db;
@@ -146,7 +145,7 @@ class DiscountAbsolute
$sql.= " fk_facture_source";
$sql.= ")";
$sql.= " VALUES (now(), ".$this->fk_soc.", ".$user->id.", '".addslashes($this->desc)."',";
$sql.= " '".$this->amount_ht."','".$this->amount_tva."','".$this->amount_ttc."','".$this->tva_tx."',";
$sql.= " ".$this->amount_ht.", ".$this->amount_tva.", ".$this->amount_ttc.", ".$this->tva_tx.",";
$sql.= " ".($this->fk_facture_source?"'".$this->fk_facture_source."'":"null");
$sql.= ")";
@@ -289,26 +288,34 @@ class DiscountAbsolute
/**
* \brief Renvoie montant TTC des avoirs en cours disponibles
* \param fk_soc Filtre sur une societe
* \brief Renvoie montant TTC des reductions/avoirs en cours disponibles
* \param company Object third party for filter
* \param user Filtre sur un user auteur des remises
* \param filter Filtre autre
* \param maxvalue Filter on max value for discount
* \return int <0 si ko, montant avoir sinon
*/
function getAvailableDiscounts($company='', $user='',$filter='')
function getAvailableDiscounts($company='', $user='',$filter='', $maxvalue=0)
{
$sql = "SELECT SUM(rc.amount_ttc) as amount";
// $sql = "SELECT rc.amount_ttc as amount";
$sql.= " FROM ".MAIN_DB_PREFIX."societe_remise_except as rc";
$sql.= " WHERE (rc.fk_facture IS NULL AND rc.fk_facture_line IS NULL)"; // Available
if (is_object($company)) $sql.= " AND rc.fk_soc = ".$company->id;
if (is_object($user)) $sql.= " AND rc.fk_user = ".$user->id;
if ($filter) $sql.=' AND '.$filter;
if ($maxvalue) $sql.=' AND rc.amount_ttc <= '.price2num($maxvalue);
dolibarr_syslog("Discount::getAvailableDiscounts sql=".$sql,LOG_DEBUG);
dolibarr_syslog("DiscountAbsolute::getAvailableDiscounts sql=".$sql,LOG_DEBUG);
$resql=$this->db->query($sql);
if ($resql)
{
$obj = $this->db->fetch_object($resql);
//while ($obj)
//{
//print 'zz'.$obj->amount;
//$obj = $this->db->fetch_object($resql);
//}
return $obj->amount;
}
return -1;
@@ -325,7 +332,7 @@ class DiscountAbsolute
$sql.= ' FROM '.MAIN_DB_PREFIX.'societe_remise_except as rc';
$sql.= ' WHERE rc.fk_facture = '.$invoice->id;
dolibarr_syslog("Discount::getSommeCreditNote sql=".$sql,LOG_DEBUG);
dolibarr_syslog("DiscountAbsolute::getSommeCreditNote sql=".$sql,LOG_DEBUG);
$resql=$this->db->query($sql);
if ($resql)
{

View File

@@ -752,8 +752,10 @@ class Form
* \param selected Id remise fixe pr<70>-s<>lectionn<6E>e
* \param htmlname Nom champ formulaire
* \param filter Criteres optionnels de filtre
* \param maxvalue Max value for lines that can be selected
* \return int Return number of qualifed lines in list
*/
function select_remises($selected='',$htmlname='remise_id',$filter='',$socid)
function select_remises($selected='',$htmlname='remise_id',$filter='',$socid, $maxvalue=0)
{
global $langs,$conf;
@@ -771,6 +773,9 @@ class Form
{
print '<select class="flat" name="'.$htmlname.'">';
$num = $this->db->num_rows($resql);
$qualifiedlines=$num;
$i = 0;
if ($num)
{
@@ -785,21 +790,27 @@ class Form
//$desc.=$obj->fk_facture_source;
}
if ($selected > 0 && $selected == $obj->rowid)
$selectstring='';
if ($selected > 0 && $selected == $obj->rowid) $selectstring=' selected="true"';
$disabled='';
if ($maxvalue && $obj->amount_ttc > $maxvalue)
{
print '<option value="'.$obj->rowid.'" selected="true">'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
}
else
{
print '<option value="'.$obj->rowid.'">'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
$qualifiedlines--;
$disabled=' disabled="true"';
}
print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
$i++;
}
}
print '</select>';
return $qualifiedlines;
}
else {
else
{
dolibarr_print_error($this->db);
return -1;
}
}
@@ -2257,14 +2268,15 @@ class Form
/**
* \brief Affiche formulaire de selection de la remise fixe
* \param page Page
* \param selected Valeur a appliquer
* \param page Page URL where form is shown
* \param selected Value pre-selected
* \param htmlname Nom du formulaire select. Si none, non modifiable
* \param socid
* \param amount
* \param filter Filtre
* \param socid Third party id
* \param amount Total amount available
* \param filter SQL filter on discounts
* \param maxvalue Max value for lines that can be selected
*/
function form_remise_dispo($page, $selected='', $htmlname='remise_id',$socid, $amount, $filter='')
function form_remise_dispo($page, $selected='', $htmlname='remise_id',$socid, $amount, $filter='', $maxvalue=0)
{
global $conf,$langs;
if ($htmlname != "none")
@@ -2278,12 +2290,17 @@ class Form
// print $langs->trans("AvailableGlobalDiscounts").': ';
$newfilter='fk_facture IS NULL AND fk_facture_line IS NULL'; // Remises disponibles
if ($filter) $newfilter.=' AND '.$filter;
print $this->select_remises('',$htmlname,$newfilter,$socid);
$nbqualifiedlines=$this->select_remises('',$htmlname,$newfilter,$socid,$maxvalue);
print '</td>';
print '<td align="left"> <input type="submit" class="button" value="';
print '<td align="left">';
if ($nbqualifiedlines > 0)
{
print ' <input type="submit" class="button" value="';
if (! $filter || $filter=='fk_facture_source IS NULL') print $langs->trans("UseDiscount");
else print $langs->trans("UseCreditNoteInInvoicePayment");
print '"></td>';
print '">';
}
print '</td>';
print '</tr></table></form>';
}
else

View File

@@ -1955,14 +1955,14 @@ function vatrate($rate,$addpercent=false,$info_bits=0)
/**
* \brief Fonction qui retourne un montant mon<6F>taire format<61> pour visualisation
* \remarks Fonction utilis<EFBFBD>e dans les pdf et les pages html
* \brief Fonction qui formate un montant pour visualisation
* \remarks Fonction utilisee dans les pdf et les pages html
* \param amount Montant a formater
* \param html Formatage html ou pas (0 par defaut)
* \param html Type de formatage, html ou pas (par defaut)
* \param outlangs Objet langs pour formatage text
* \param trunc 1=Tronque affichage si trop de d<EFBFBD>cimales,0=Force le non troncage
* \param trunc 1=Tronque affichage si trop de decimales,0=Force le non troncage
* \param nbdecimal Nbre decimals minimum.
* \return string Chaine avec montant format<EFBFBD>
* \return string Chaine avec montant formate
* \seealso price2num Fonction inverse de price
*/
function price($amount, $html=0, $outlangs='', $trunc=1, $nbdecimal=2)
@@ -2021,7 +2021,7 @@ function price($amount, $html=0, $outlangs='', $trunc=1, $nbdecimal=2)
* \remarks Fonction a 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_TOT)
* 'MT'=Round to Max for totals with Tax (MAIN_MAX_DECIMALS_TOT)
* 'MS'=Round to Max Shown (MAIN_MAX_DECIMALS_SHOWN)
* ''=No rounding
* \return string Montant au format num<75>rique PHP et SQL (Exemple: '99.99999')

View File

@@ -1024,17 +1024,18 @@ class Societe extends CommonObject
/**
* \brief Renvoie montant TTC des avoirs en cours disponibles de la societe
* \brief Renvoie montant TTC des reductions/avoirs en cours disponibles de la societe
* \param user Filtre sur un user auteur des remises
* \param filter Filtre autre
* \param maxvalue Filter on max value for discount
* \return int <0 if KO, Credit note amount otherwise
*/
function getAvailableDiscounts($user='',$filter='')
function getAvailableDiscounts($user='',$filter='',$maxvalue=0)
{
require_once(DOL_DOCUMENT_ROOT.'/discount.class.php');
$discountstatic=new DiscountAbsolute($this->db);
$result=$discountstatic->getAvailableDiscounts($this,$user,$filter);
$result=$discountstatic->getAvailableDiscounts($this,$user,$filter,$maxvalue);
if ($result >= 0)
{
return $result;
@@ -1046,6 +1047,13 @@ class Societe extends CommonObject
}
}
/**
* Enter description here...
*
* @param unknown_type $price_level
* @param unknown_type $user
*/
function set_price_level($price_level, $user)
{
if ($this->id)