Correct cents in boletoPHP bank statements

5

I am using the BoletoPHP project to generate bank notes, but I noticed that the cents are not recorded properly, because when I buy a product with the value of for example, $ 245.00 plus the bank fee $ 2.95 , it correctly prints the value of $ 247.95.

But when I buy a product with the value of 2,399.99 plus the bank fee of $ 2.95, it prints the value of $ 2,401.95, when the correct would be $ 2,402.94. >

In other words, it ignores the penny of the goods, but does not ignore the cents of the bank rate.

Friends could tell me where I'm going wrong, or what would be the solution for him to print the product cents as well.

In the database I'm writing to the column as type "decimal (10,2)".

Below I relate the line of code of the ticket for the value.

   $dias_de_prazo_para_pagamento = 5;
   $taxa_boleto = 2.95;
   $data_venc = date("d/m/Y", time() + (5 * 86400));  // Prazo de X dias OU informe data: "13/04/2006"; 
   $valor_cobrado = $_POST["total"]; // Valor - REGRA: Sem pontos na milhar e tanto faz com "." ou "," ou com 1 ou 2 ou sem casa decimal
   $valor_cobrado = str_replace(".", "",$valor_cobrado);
   $valor_boleto=number_format($valor_cobrado+$taxa_boleto,2,",",".");

Below I relate the form's line of code to the value.

   <?php
   if(count($_SESSION['carrinho']) == 0){
      echo '<tr><td colspan="5">Não há produto no carrinho</td></tr>';
   }else{
      require("conexao.php");
   $total = 0;
      foreach($_SESSION['carrinho'] as $codigo => $qtd){
   $sql   = "SELECT * FROM produto WHERE codigo= '$codigo'";
   $qr    = mysql_query($sql) or die(mysql_error());
   $ln    = mysql_fetch_assoc($qr);

   $titulo  = $ln['titulo'];
   $preco = number_format($ln['preco'], 2, ',', '.');
   $sub   = number_format($ln['preco'] * $qtd, 2, ',', '.');

   $total += $ln['preco'] * $qtd;

      echo '<tr style="font-size:11px; font-weight:bold; color:#000;">       
                <td  align="left">'.$titulo.'</td>
                <td align="center">'.$qtd.'</td>
                <td align="center">R$ '.$preco.'</td>
                <td align="center">R$ '.$sub.'</td>
                <td align="center"><a href="?acao=del&codigo='.$codigo.'">
                <img width="25" src="img/del.png" title="Remover '.$titulo.'"/>
                </a></td>
             </tr>';
    }
    $total = number_format($total, 2, ',', '.');
       echo '<tr></tr><tr></tr><tr></tr><tr></tr><tr></tr>
             <tr>
                <td align="right" style="font-size:16px; font-weight:bold; color:#990000;" colspan="3">Total</td>
                <td align="left" style="font-size:16px; font-weight:bold; color:#000;" colspan="4">R$ '.$total.'</td>
              </tr>';
    }
    ?>

How do I get the ticket to print the product cents?

    
asked by anonymous 16.12.2015 / 13:28

3 answers

3

The problem is that PHP, like all languages, does not work well with precise monetary values.

I find it curious that a program ready to work with monetary values does not deal well with this.

You have several questions here , but so far nobody has wanted to do a specific for PHP.

The processor works fine with decimal values but for performance it does it with base 2. So you can not accurately represent all values.

Most programmers do not know this and cause problems for users of their software. The difference may be a penny, but if you multiply 1 cent per 1 million, it gives ten thousand reais of injury to one side or the other. It may lead to prosecution or fine in supervision.

So you need to treat monetary values differently. MySQL has a proper form, several languages have a data type that handles the number in another way to avoid this problem of accuracy. All treatment should be done on base 10. This is usually done with an integer and scale to represent the decimal part. Entire numbers do not suffer from this problem. This can be done transparently in many languages. This is not the case with PHP.

The solution is to do manual, or create a new data type that encapsulates this logic, or use something ready.

Manually treats the values by the cents for all accounts and only in the presentation use the comma. If you treat the numbers by the cents, an integer solves the problem. At the end of having 245.00 reais, you will have 24500 cents.

Of course you have to know how to do some operations, such as multiplication and division so as not to give scale problem. Divisions and multiplications by 100 will be common (assuming there are two decimal places).

To avoid always doing this and forgetting something, some people encapsulate this into a Decimal or Money class by abstracting operations a bit and making the usage more natural.

There are some of these classes ready. PHP itself has an add-on module called BCMath . I do not like it very much, but it's a ready-made solution.

In any case the presentation of the data is different from the data itself. It is no use solving the presentation problem if the calculations, which is the important thing, remain wrong.

    
16.12.2015 / 13:49
3

The account made by PHP is right 2399 plus 2.95 is 2,401.95. This happens because when you transform the string 2.399,99 into float the 99 of the cents is discarded because the separated one is . and not virgin.

A string where the first character is a number, PHP will treat this as a number so the expression "2 + '6 apples' "equals 8?

$a = 10;
$b = (float)'20,1';

echo $a + $b;

The expected result would be 30.1 right? no !, only 20 is considered a numerical value, for the expected result the value should be 20.1. If the value of $b was 20#%$99 and added to $a the output would still be 30 .

Error Simulation:

$taxa_boleto = 2.95;
$valor_cobrado = '2.399,99';
$valor_cobrado =  str_replace(".", "", $valor_cobrado);
$res = $valor_cobrado + $taxa_boleto;
$valor_boleto = number_format($valor_cobrado + $taxa_boleto, 2, ",", ".");

The output is 2401.95. The account made was 2399 + 2.95

Solution of the changed tab of , by .

$taxa_boleto = 2.95;
$valor_cobrado = '2.399,99';
$valor_cobrado =  str_replace(".", "", $valor_cobrado);
$valor_cobrado =  str_replace(",", ".", $valor_cobrado); //linha adicionada
$res = $valor_cobrado + $taxa_boleto;
echo $res;

Output: 2402.94. The account made was 2399.99 + 2.95

    
16.12.2015 / 14:45
0

Hello, I would like to thank the rray because with your tip I was able to make the ticket correctly print "(including the product cents)" the values of the products added or not the bank fees.

I've changed the following lines below the code.

Ignoring Product Cents - Wrong

 $valor_cobrado = str_replace(".", "",$valor_cobrado);
 $valor_boleto=number_format($valor_cobrado+$taxa_boleto,2,",",".");

Including Product Cents - Correct

 $valor_cobrado = str_replace(",", "",$valor_cobrado);
 $valor_boleto=number_format($valor_cobrado+$taxa_boleto,2,".",".");

I tested on banks' tickets: Banco do Brasil, Caixa Econômica, Itaú, Bradesco, Santander, and it worked in all.

I hope it helps other BoletoPHP users.

Thanks for the help.

    
16.12.2015 / 15:37