Mongoose-Currency-BRL
Menção honrosa a @paulcsmith por disponibilizar o repositório original que tornou este pacote possível.
O que isto faz
- Salva uma String como Integer (remove não dígitos e multiplica por 100) para prevenir erros de arredondamento ao realizar cálculos (Ver "Sacadas" para detalhes)
- Remove símbolos da string (como símbolo da moeda
$
ouR$
) - Remove pontos (e.g.
"1.000,50"
=>100050
) - Salva apenas os dois primeiros digitos da parte decimal (
"R$ 500,559"
é convertido para50055
e não arredonda) - Remove [a-zA-Z] das strings
- Aceita strings e números. Número serão armazenados tal como informado.
- Se um ponto flutuante for passado, ele será arredondado. (
500.55
=>501
). Use apenas inteiros ou strings por segurança.
Como usar
import mongoose from "mongoose";
import { BrazilianCurrency } from "@logicamente.info/mongoose-currency-brl";
// Adicione o tipo BrazilianCurrency ao Mongoose (necessário uma única vez, sugestão: coloque no arquivo de criação da conexão)
BrazilianCurrency.loadType(mongoose);
const ProdutoSchema = Schema({
preco: { type: BrazilianCurrency }
});
const Produto = mongoose.model('Produto', ProdutoSchema);
const produto = new Produto({ preco: "R$ 1.200,55" });
produto.preco; // Número: 120055
produto.preco = 1200;
produto.preco; // Número 1200 não irá arredondar ou multiplicar e deve representar R$ 12,00
Schema options
Aceita o esquema de opções de números do mongoose.
// Irá validar se o mínimo é R$ 200,00 e o máximo é R$ 500,00
var ProdutoSchema = Schema({
preco: { type: BrazilianCurrency, required: true, min: -20000, max: 50000 }
});
Exibindo para usuários finais (telas, relatórios, etc.)
Para exibir os valores aos usuários finais, lembre-se de dividir por 100, e na sequência você pode mascarar o resultado.
// Se produto.preco = 120055
const preco = produto.preco / 100; // Retorna 1200.55
const opcoes = { style: 'currency', currency: 'BRL' };
Intl.NumberFormat('pt-BR', opcoes).format(preco); // Retorna R$ 1.200,55
Testando
Na raiz do diretório do projeto, execute npm test
Sacadas
O valor é armazenado e retornado como um inteiro. Por que? Porque somar dois pontos flutuantes pode causar erros de arredondamento.
// Isso não é bom
1.03 + 1.19; // 2.2199999999999998
Cálculos com valores usando mongoose-currency-brl
const produto1 = Produto.findById('id1');
const produto2 = Produto.findById('id2');
produto1.preco; // retorna 103 que representa R$ 1,03
produto2.preco; // retorna 119 que representa R$ 1,19
const soma = (produto1.preco + produto2.preco) / 100; // = 222
soma / 100; // retorna um número decimal: 2.22
Exibindo valores para usuários finais
const opcoes = { style: 'currency', currency: 'BRL' };
const registro = Produto.findById('id');
registro.preco; // Supondo 10050
Intl.NumberFormat('pt-BR', opcoes).format(preco); // R$ 100,50
Quando você atribui um inteiro, ele NÃO será multiplicado por 100. Será armazenado tal como é! Isto é de propósito, pois esta biblioteca foi criada principalmente para aceitar entradas realizadas por USUÁRIOS.
produto.preco = 100;
produto.preco; // Retorna 100 e não multiplica por 100. Representa R$ 1,00
Consultas e validadores
Lembre-se que ao fazer consultas para encontrar valores maiores que, menores que, etc. você precisará multiplicar por 100!
Então para retornar valores maiores que R$ 100,00 você precisará realizar a consulta com 100 * 100 e.g. 10000
Esta é considerada uma boa prática para armazenar valores monetários como inteiros. Causará muito menos problemas pelo caminhho
Para uma leitura mais aprofundada: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Apenas lembre-se dividir por 100 toda vez que você quiser exibir os valores para o usuário.