Trabalhando com valores monetários em Apps Flutter

Trabalhar com valores monetários em aplicativos é uma parte crítica do desenvolvimento de software, especialmente em soluções de e-commerce, fintechs e apps que lidam com finanças. É necessário cuidado adicional ao trabalhar com operações de moeda para…


This content originally appeared on DEV Community and was authored by Enrique Marques Junior

Trabalhar com valores monetários em aplicativos é uma parte crítica do desenvolvimento de software, especialmente em soluções de e-commerce, fintechs e apps que lidam com finanças. É necessário cuidado adicional ao trabalhar com operações de moeda para evitar problemas como arredondamento incorreto, perda de precisão ou conversões inadequadas. Este artigo explora boas práticas, ferramentas e abordagens para manipular valores monetários em apps Flutter.

1. Evitando o Uso de double para Valores Monetários

No Dart, o tipo double é frequentemente utilizado para representar números float. Porem, este não é o tipo adequado para valores monetários, pois números em ponto flutuante introduzem imprecisões. Por exemplo:

void main() {
  final double value = 0.1 + 0.2;
  print(value); // Output: 0.30000000000000004
}

Essa imprecisão pode parecer insignificante em alguns casos, mas pode ter consequências sérias quando se trata de valores financeiros.

Usar Inteiros para Representar Centavos

Uma prática é representar valores monetários em centavos utilizando int, evitando o uso de decimais e a imprecisão associada a double. Por exemplo, R$ 12,34 seria representado como 1234.

void main() {
  final int value = 1234;
  final double decimal = value / 100;
  print(decimal); // Output: 12.34
}

2. Usando a Biblioteca intl para Formatação Monetária

A biblioteca intl é uma ferramenta boa para lidar com internacionalização e formatação de números, inclusive valores monetários. Ela permite formatar números com o símbolo de moeda correto e de acordo com as convenções locais.

Exemplo de Formatação de Valores Monetários

import 'package:intl/intl.dart';

void main() {
  final int value = 1234;
  final format = NumberFormat.simpleCurrency(locale: 'pt_BR').format;
  final double decimal = value / 100;

  print(format(decimal)); // Output: R$12,34
}

Aqui, usamos NumberFormat.simpleCurrency com a localidade brasileira (pt_BR) para formatar o valor corretamente em reais.

3. Operações Seguras com Moeda

Operações financeiras como adição, subtração, multiplicação e divisão precisam ser feitas com cautela para evitar erros de precisão. A melhor prática é realizar todas as operações em centavos e, somente para exibição, converter o valor para o formato apropriado.

Exemplo de Adição de Valores Monetários

void main() {
  final int value = 1234; // R$12,34
  final int value2 = 5678; // R$56,78
  final int sum = value + value2;
  print('Soma em centavos: $sum'); // Output: 6912
  final double decimal = sum / 100;
  print('Soma em reais: $decimal'); // Output: 69.12
}

4. Trabalhando com Taxas e Porcentagens

Um caso comum ao lidar com valores monetários é a aplicação de taxas ou porcentagens, como taxas de juros ou descontos. A dica aqui é evitar o uso de double diretamente em operações que envolvam porcentagens, convertendo sempre o resultado final para centavos antes de exibir.

Exemplo: Aplicando Desconto

void main() {
  final int original = 10000; // R$100,00
  final double discount = 0.15; // 15%

  final int total = (original * (1 - discount)).round();
  print('Valor com desconto: ${total / 100}'); // Output: 85.00
}

Aqui usamos a função round() para garantir que o valor seja arredondado corretamente após a aplicação do desconto, evitando problemas de precisão.

5. Trabalhando com Casas Decimais e Arredondamento

Ao lidar com moedas, é comum precisar exibir ou operar com um número específico de casas decimais. A biblioteca intl facilita o arredondamento e a formatação desses valores. No entanto, ao realizar operações matemáticas, é importante controlar o arredondamento corretamente.

Exemplo de Arredondamento

import 'package:intl/intl.dart';

void main() {
  final double value = 1234.56789;
  final formatter = NumberFormat("#,##0.00", "pt_BR");

  print(formatter.format(value)); // Output: 1.234,57
}

6. Mascara de Valores

No Flutter, podemos utilizar o pacote extended_masked_text para aplicar uma máscara ao valor digitado, permitindo que ele seja formatado automaticamente enquanto o usuário insere a quantia.

  • Exemplo de TextField com máscara e validação:
import 'package:flutter/material.dart';
import 'package:extended_masked_text/extended_masked_text.dart';
import 'package:intl/intl.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Validação de Valores Monetários'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: MonetaryTextField(),
        ),
      ),
    );
  }
}

class MonetaryTextField extends StatefulWidget {
  const MonetaryTextField({super.key});

  @override
  createState() => _MonetaryTextFieldState();
}

class _MonetaryTextFieldState extends State<MonetaryTextField> {
  final _controller = MoneyMaskedTextController(leftSymbol: 'R\$ ');

  String? _errorText;

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      keyboardType: TextInputType.number,
      decoration: InputDecoration(
        labelText: 'Valor',
        border: const OutlineInputBorder(),
        errorText: _errorText,
      ),
      inputFormatters: [
        FilteringTextInputFormatter.digitsOnly,
      ],
      onChanged: (value) {
        setState(() {
          _errorText = _validateInput(value);
        });
      },
    );
  }

  String? _validateInput(String value) {
    if (value.isEmpty) {
      return 'Por favor, insira um valor';
    }

    final numericValue = _controller.numberValue;
    if (numericValue <= 0) {
      return 'O valor deve ser maior que zero';
    }

    return null;
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

Conversão de Valores para Centavos

Uma prática comum ao armazenar valores financeiros é convertê-los para centavos, o que aumenta a precisão ao evitar erros de arredondamento. Neste caso, seria:

final int value = (_controller.numberValue * 100).round()

Exemplo: se o usuário inserir 1,234.56, o valor será convertido para 123456 centavos, garantindo que o dado seja armazenado corretamente.

Agora, além de validar e mascarar os valores monetários, você também consegue sanitizá-los de forma mais eficiente e realizar a conversão para centavos de forma precisa e segura, utilizando o pacote intl.

Armazenando a Moeda

Além de salvar o valor em centavos, é essencial armazenar a moeda associada a esse valor. Aplicativos frequentemente lidam com múltiplas moedas e associar cada valor à sua moeda permite o tratamento correto nas operações e na exibição.

Por exemplo, para um produto com preço em dólares:

  • Valor em centavos (int): 4567 (representando $45.67)
  • Moeda (string): USD

Isso garante que, ao exibir o valor ao usuário, o aplicativo possa formatá-lo corretamente como $45.67, preservando a moeda adequada.

Extra: packages

Aqui estão alguns pacotes que ajudam a lidar com valores monetários em Dart, fornecendo soluções mais robustas para cálculos financeiros, formatação e manipulação de moedas:

1. money2

O pacote money2 oferece uma API completa para lidar com valores monetários em qualquer moeda. Ele ajuda a resolver problemas comuns de precisão e formatação ao trabalhar com valores financeiros.

Recursos principais:

  • Representação de valores em diferentes moedas.
  • Manipulação segura de operações financeiras.
  • Arredondamento configurável e suporte para múltiplas casas decimais.
  • Integração com intl para formatação.

Exemplo:

import 'package:money2/money2.dart';

void main() {
  final currency = Currency.create('BRL', 2, symbol: 'R\$');
  final value = Money.fromInt(12345, currency); // R$123,45
  print(value.format('S0.00')); // Output: R$123.45
}

2. decimal

O pacote decimal é ideal para quem precisa de precisão exata em operações numéricas, evitando as limitações do tipo double. É muito útil em cálculos financeiros onde a precisão é crítica.

Recursos principais:

  • Suporta números com precisão arbitrária.
  • Ideal para cálculos que envolvem valores monetários grandes ou complexos.

Exemplo:

import 'package:decimal/decimal.dart';

void main() {
  final value1 = Decimal.parse('10.25');
  final value2 = Decimal.parse('20.35');
  final result = value1 + value2;

  print(result); // Output: 30.60
}

3. money_formatter

O money_formatter é um pacote simples e eficiente para formatação de valores monetários, fornecendo diferentes opções de exibição e manipulação. Ele é útil se você precisa apenas de formatação, sem operações matemáticas complexas.

Recursos principais:

  • Formatação flexível e suporte para múltiplas moedas.
  • Suporte para arredondamento e exibição de valores em diferentes formatos.

Exemplo:

import 'package:money_formatter/money_formatter.dart';

void main() {
  final fmf = MoneyFormatter(amount: 1234567.89);
  print(fmf.output.symbolOnLeft); // Output: $1,234,567.89
}

4. currency_formatter

O currency_formatter é outra alternativa para lidar com a formatação de valores monetários, mas ele também inclui opções de conversão entre moedas, o que pode ser útil se o seu aplicativo precisa exibir múltiplas moedas.

Recursos principais:

  • Conversão de moedas usando taxas de câmbio.
  • Formatação de moedas com suporte para diferentes locais.

Exemplo:

import 'package:currency_formatter/currency_formatter.dart';

void main() {
  final formatter = CurrencyFormatter();
  final formattedValue = formatter.format(123456.78, CurrencyFormatterSettings(symbol: 'R\$', symbolSide: SymbolSide.left));

  print(formattedValue); // Output: R$123,456.78
}

É isso! :)

Foto de Eric Prouzet na Unsplash


This content originally appeared on DEV Community and was authored by Enrique Marques Junior


Print Share Comment Cite Upload Translate Updates
APA

Enrique Marques Junior | Sciencx (2024-10-08T17:11:42+00:00) Trabalhando com valores monetários em Apps Flutter. Retrieved from https://www.scien.cx/2024/10/08/trabalhando-com-valores-monetarios-em-apps-flutter/

MLA
" » Trabalhando com valores monetários em Apps Flutter." Enrique Marques Junior | Sciencx - Tuesday October 8, 2024, https://www.scien.cx/2024/10/08/trabalhando-com-valores-monetarios-em-apps-flutter/
HARVARD
Enrique Marques Junior | Sciencx Tuesday October 8, 2024 » Trabalhando com valores monetários em Apps Flutter., viewed ,<https://www.scien.cx/2024/10/08/trabalhando-com-valores-monetarios-em-apps-flutter/>
VANCOUVER
Enrique Marques Junior | Sciencx - » Trabalhando com valores monetários em Apps Flutter. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/10/08/trabalhando-com-valores-monetarios-em-apps-flutter/
CHICAGO
" » Trabalhando com valores monetários em Apps Flutter." Enrique Marques Junior | Sciencx - Accessed . https://www.scien.cx/2024/10/08/trabalhando-com-valores-monetarios-em-apps-flutter/
IEEE
" » Trabalhando com valores monetários em Apps Flutter." Enrique Marques Junior | Sciencx [Online]. Available: https://www.scien.cx/2024/10/08/trabalhando-com-valores-monetarios-em-apps-flutter/. [Accessed: ]
rf:citation
» Trabalhando com valores monetários em Apps Flutter | Enrique Marques Junior | Sciencx | https://www.scien.cx/2024/10/08/trabalhando-com-valores-monetarios-em-apps-flutter/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.