Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

BaDcereal

[Resolvido] PHP/MySQL - Trabalhando com Valores Monetários com pr

Recommended Posts

PHP/MySQL - Trabalhando com Valores Monetários com precisão em casas decimais.

 

Esses dias me deparei com um problema no trabalho, estava desenvolvendo um sistema de administração interno para empresa onde envolvia cálculos monetários. O problema ocorreu quando tentei gravar no banco um numero com mais de 8 dígitos e 2 casas decimais de precisão. Primeiramente tentei usar o tipo de dados DOUBLE mas ele truncava as casas decimais. Exp.: eu inseria no banco 3.456.234.678,98 e na consulta ele me trazia 3.456.234.679,00

Moral da historia, ele estava truncando as casas decimais. Testei com o tipo FLOAT e obtive os mesmos resultados do tipo DOUBLE. Então depois de pesquisar na internet e nada encontrar que solucionasse meu problema, resolvi ler o manual do MySQL e encontrei o seguinte:

"Os tipos de dados FLOAT e DOUBLE são usados para representar aproximadamente dados de valores numéricos."

Mais adiante no manual encontrei o tipo DECIMAL que dizia:

"Os tipos de dados DECIMAL e NUMERIC são usados para armazenar dados de valores numéricos com precisão. Eles são usados por valores para os quais é importante preservar a exatidão como, por exemplo, dados monetários."Esse era o cara que eu estava procurando ;)

Sem mais delongas vamos ao que interessa a implementação. Não vou entrar em muitos detalhes quem estiver interessado em saber mais sobre os tipos de dados que o MySQL suporta pode consultar o manual nos links abaixo:

 

Manual de Referência do MySQL 4.1 / 6.2.1. Tipos Numéricos – em português

http://dev.mysql.com...1/pt/index.html

 

MySQL 5.5 Reference Manual / 10.2. Numeric Types – em inglês

http://dev.mysql.com...5/en/index.html

 

Implementação:

 

MySQL

No MySQL configure sua tabela para receber o tipo de dado DECIMAL.

DECIMAL(M,D) onde M é o numero de dígitos e D o numero de casas decimais.

Exp.: salário DECIMAL(5,2) ele ira suportar a faixa numérica de -999.99 to 999.99

Se não for especificado nada entre parênteses ele assume o valor padrão M é 10. Ok depois de configurado o MySQL devidamente vamos ao PHP.

 

PHP

Primeiramente devemos remover a virgula e substituir ela por ponto porque o MySQL usa o padrão americano para gravar os dados. Escrevi uma pequena função para fazer isso:

function moeda($get_valor) {
	$source = array('.', ','); 
	$replace = array('', '.');
	$valor = str_replace($source, $replace, $get_valor); //remove os pontos e substitui a virgula pelo ponto
	return $valor; //retorna o valor formatado para gravar no banco
}

//Chamada da função
$valor_final=moeda($_POST['valor']);

 

Ok tudo gravado no banco muito bonito, mas agora quando você fizer um SELECT ele não ira trazer o valor com deve. Para isso precisamos usar a função do PHP number_format()

 

Abaixo a solução:

$valor_servico = ' R$ ' . number_format($l['valor_servico'], 2, ',', '.');

 

O que exatamente faz essa linha? number_format pega o valor da variável $l que foi buscada no banco, separa as ultimas 2 casas a direita com uma virgula depois a cada 3 casa ele coloca um ponto a seguir concatena co valor com R$ para ficar bonitinho e armazena o resultado na variável $valor_servico

 

Pronto, não entrei em muitos detalhes mas acho que consegui passar o conceito para vocês.

Até a próxima.

Compartilhar este post


Link para o post
Compartilhar em outros sites

function convertCoin($xCoin = "EN", $xDecimal = 2, $xValue) {
   $xValue       = preg_replace( '/[^0-9]/', '', $xValue); // Deixa apenas números
   $xNewValue    = substr($xValue, 0, -$xDecimal); // Separando número para adição do ponto separador de decimais
   $xNewValue    = ($xDecimal > 0) ? $xNewValue.".".substr($xValue, strlen($xNewValue), strlen($xValue)) : $xValue;
   return $xCoin == "EN" ? number_format($xNewValue, $xDecimal, '.', '') : ($xCoin == "BR" ? number_format($xNewValue, $xDecimal, ',', '.') : NULL);
}
$xValue = "12345678"; // Podendo ser "R$ 123.456,78" ou somente "123.456,78" ou "123456,78" ou "123.45678"

convertCoin("EN",0,$xValue); // 12345678
convertCoin("EN",1,$xValue); // 1234567.8
convertCoin("EN",2,$xValue); // 123456.78
convertCoin("EN",3,$xValue); // 12345.678

convertCoin("BR",0,$xValue); // 12.345.678
convertCoin("BR",1,$xValue); // 11.234.567,8
convertCoin("BR",2,$xValue); // 123.456,78
convertCoin("BR",3,$xValue); // 12.345,678

 

Fiz uma função pra melhorar a conversão de mão dupla.

Convertendo antes de enviar pro banco, e depois de pegar do banco.

Tenho quase toda certeza que ela pode ser melhorada pela galera que tem mais conhecimento...

Mas já ta sendo bem satisfatório pra mim o resultado da mesma.

Espero ter ajudado!

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.