14 KiB
Story 2.2: Calcular Acréscimo ao Selecionar Forma de Pagamento
Status: done
Story
Como representante de vendas, quero que o acréscimo seja calculado e exibido automaticamente ao selecionar a forma de pagamento, para que eu veja o valor real do pedido sem precisar calcular manualmente.
Acceptance Criteria
-
Dado que estou editando um pedido com subtotal R$ 3.500,00 Quando selecionar "Boleto 30/60/90" com
tx_acrescimo = 2.5Então o campo "Acréscimo" exibe R$ 87,50 e o total exibe R$ 3.587,50 -
Dado que já selecionei "Boleto 30/60/90" (2,5%) e troco para "Dinheiro" (
tx_acrescimo = 0) Quando a forma de pagamento for alterada Então o campo "Acréscimo" retorna a R$ 0,00 e o total retorna a R$ 3.500,00 -
Dado que a forma de pagamento selecionada tem
tx_acrescimo = NULL(zero no VO após Story 1.2) Quando o cálculo for executado Então acréscimo = R$ 0,00, sem crash ouNullPointerException -
Dado que o cálculo é disparado Quando a troca de forma de pagamento ocorrer Então o recálculo conclui em menos de 100ms (aritmética em memória, sem I/O)
Escopo desta história
Esta história cobre exclusivamente o cálculo em memória e exibição do acréscimo ao selecionar forma de pagamento.
- NÃO persiste o valor no banco — persistência é escopo da Story 2.3
- NÃO adiciona campos novos na UI — campos
tvAcrescimoPedidoetvAcrescimoforam criados na Story 2.1 - NÃO lê do SQLite durante a seleção —
tx_acrescimojá está no objetoFormaPagamentoem memória
Tasks / Subtasks
-
Task 1: Atualizar cálculo em
MainPedidoFragment.atualizarResumoPedido()(AC: 1, 2, 3, 4)- 1.1 — Na linha ~974 de
MainPedidoFragment.java, substituir o bloco placeholder:Por:double vlAcrescimo = 0.0; // Story 2.2 calculara: subtotal * (tx_acrescimo/100) tvAcrescimoPedido.setText(Util.formataValorMonetario(vlAcrescimo)); tvTotalGeral.setText(Util.formataValorMonetario(totalGeral));double txAcrescimo = 0.0; if (Global.pedido.getFormapag() != null) { txAcrescimo = Global.pedido.getFormapag().getTxAcrescimo(); } double vlAcrescimo = totalGeral * (txAcrescimo / 100.0); tvAcrescimoPedido.setText(Util.formataValorMonetario(vlAcrescimo)); tvTotalGeral.setText(Util.formataValorMonetario(totalGeral + vlAcrescimo));
- 1.1 — Na linha ~974 de
-
Task 2: Atualizar cálculo em
MainPedidoFragment.fillFields()(AC: 1, 2, 3)- 2.1 — Na linha ~439 de
MainPedidoFragment.java, substituir o bloco placeholder:Pelo mesmo padrão da Task 1.1 (idêntico —double vlAcrescimo = 0.0; // Story 2.2 calculara: subtotal * (tx_acrescimo/100) tvAcrescimoPedido.setText(Util.formataValorMonetario(vlAcrescimo)); tvTotalGeral.setText(Util.formataValorMonetario(totalGeral));fillFields()usa as mesmas variáveis locaistotalGeral).
- 2.1 — Na linha ~439 de
-
Task 3: Atualizar cálculo em
TotalPedidoFragment.FillFields()(AC: 1, 2, 3)- 3.1 — Na linha ~97 de
TotalPedidoFragment.java, substituir:Por:tvAcrescimo.setText(Util.formataValorMonetario(0.0)); tvTotalGeral.setText(Util.formataValorMonetario(vlTotalGeral));Atenção: a variável local emdouble txAcrescimo = 0.0; if (Global.pedido.getFormapag() != null) { txAcrescimo = Global.pedido.getFormapag().getTxAcrescimo(); } double vlAcrescimo = vlTotalGeral * (txAcrescimo / 100.0); tvAcrescimo.setText(Util.formataValorMonetario(vlAcrescimo)); tvTotalGeral.setText(Util.formataValorMonetario(vlTotalGeral + vlAcrescimo));TotalPedidoFragmentévlTotalGeral(nãototalGeralcomo emMainPedidoFragment).
- 3.1 — Na linha ~97 de
Dev Notes
Estado atual do código após Story 2.1
Ambos os métodos já possuem o placeholder exato que deve ser substituído:
MainPedidoFragment.java — atualizarResumoPedido() (linha ~974):
double vlAcrescimo = 0.0; // Story 2.2 calculara: subtotal * (tx_acrescimo/100)
tvAcrescimoPedido.setText(Util.formataValorMonetario(vlAcrescimo));
tvTotalGeral.setText(Util.formataValorMonetario(totalGeral));
MainPedidoFragment.java — fillFields() (linha ~439):
double vlAcrescimo = 0.0; // Story 2.2 calculara: subtotal * (tx_acrescimo/100)
tvAcrescimoPedido.setText(Util.formataValorMonetario(vlAcrescimo));
tvTotalGeral.setText(Util.formataValorMonetario(totalGeral));
TotalPedidoFragment.java — FillFields() (linha ~97):
tvAcrescimo.setText(Util.formataValorMonetario(0.0));
tvTotalGeral.setText(Util.formataValorMonetario(vlTotalGeral));
Fórmula de cálculo
subtotal = totalProduto - totalDesconto + totalIcmsST (+ totalIPI se !precoComIpi)
vlAcrescimo = subtotal * (tx_acrescimo / 100.0)
totalFinal = subtotal + vlAcrescimo
O subtotal já está calculado nas variáveis locais totalGeral (MainPedidoFragment) e vlTotalGeral (TotalPedidoFragment) — não recalcular.
Onde tx_acrescimo está disponível (sem I/O)
Global.pedido.getFormapag().getTxAcrescimo() retorna double diretamente — a FormaPagamento já está carregada em memória. Não há necessidade de acessar o SQLite durante o cálculo — NFR1 (< 100ms) é satisfeito trivialmente.
Null-safety obrigatória
Global.pedido.getFormapag() pode ser null (pedido sem forma de pagamento definida). getTxAcrescimo() retorna double (primitivo), então não há risco de NPE no getter, mas o objeto pai pode ser null. Padrão obrigatório:
double txAcrescimo = 0.0;
if (Global.pedido.getFormapag() != null) {
txAcrescimo = Global.pedido.getFormapag().getTxAcrescimo();
}
FormaPagamentoDB (Story 1.2) já garante que tx_acrescimo = NULL no SQLite é lido como 0.0 no VO — sem risco adicional.
Fluxo de disparo do cálculo em MainPedidoFragment
O cálculo é disparado em dois cenários:
-
Seleção de forma de pagamento —
onItemSelected()→ chamaatualizarResumoPedido()(linha 789):} else if (spFormaPag != null && parent == spFormaPag) { if ((!isFormaPagBloq && ...) || Global.pedido.getFormapag() == null){ Global.pedido.setFormapag(listForPagtos.get(pos)); atualizarResumoPedido(); // ← aqui está o gatilho } }O
Global.pedido.getFormapag()já está atualizado quandoatualizarResumoPedido()é chamado. -
Carregamento inicial do fragmento —
onResume()→Handler.post()→fillFields()→ exibe o acréscimo da forma já selecionada.
Nomes de variáveis — diferença entre os dois fragmentos
| Fragmento | Variável "subtotal" | TextView acréscimo | TextView total |
|---|---|---|---|
MainPedidoFragment |
totalGeral |
tvAcrescimoPedido |
tvTotalGeral |
TotalPedidoFragment |
vlTotalGeral |
tvAcrescimo |
tvTotalGeral |
Não confundir os nomes — são fragmentos separados com variáveis locais distintas.
TotalPedidoFragment não chama atualizarResumoPedido()
TotalPedidoFragment é independente de MainPedidoFragment. Ele recalcula tudo em FillFields(), chamado no onStart(), onResume() e setUserVisibleHint(). O campo tvAcrescimo neste fragmento mostra o acréscimo da forma de pagamento atual do Global.pedido — que já foi atualizado pelo MainPedidoFragment via Global.pedido.setFormapag(...) antes de qualquer troca de aba.
Arquivos a modificar
| Arquivo | Caminho | O que muda |
|---|---|---|
MainPedidoFragment.java |
src/br/com/jcsinformatica/sarandroid/pedido/ |
Substituir placeholder em atualizarResumoPedido() e fillFields() |
TotalPedidoFragment.java |
src/br/com/jcsinformatica/sarandroid/pedido/ |
Substituir placeholder em FillFields() |
NÃO modificar nesta história:
FormaPagamento.java—getTxAcrescimo()já existe (Story 1.2)FormaPagamentoDB.java— leitura detx_acrescimojá implementada (Story 1.2)Pedido.java— campovlAcrescimono VO não é necessário nesta história (Story 2.3 adiciona persistência)PedidoDB.java— sem mudança de banco nesta históriaDatabaseHelper.java— sem migração de schema nesta história- Layouts XML — sem mudança (campos já existem da Story 2.1)
Regras críticas do projeto (aplicáveis a esta história)
- Sem Kotlin — somente Java puro
- Sem Gradle — projeto Eclipse ADT
- Sem JARs novos — cálculo aritmético, sem dependências
- Sem testes automatizados — validação manual via emulador/dispositivo
- Strings com acentos — NÃO usar em código Java; esta história não adiciona strings novas
- SQLite em thread background — esta história NÃO lê o banco durante o cálculo, não se aplica
Verificação manual após implementação
- Abrir pedido com itens — aba Dados → selecionar forma de pagamento com
tx_acrescimo > 0→ verificar campo "Acréscimo" e "Total Geral" atualizados corretamente - Trocar para forma de pagamento com
tx_acrescimo = 0→ verificar retorno a R$ 0,00 no acréscimo e total sem acréscimo - Navegar para aba Total → verificar que
tvAcrescimoetvTotalGeralrefletem o mesmo valor calculado - Abrir pedido sem forma de pagamento definida → sem crash; acréscimo = R$ 0,00
- Conferir:
3500 × 2,5% = 87,50e3500 + 87,50 = 3587,50nos campos visuais
Inteligência de histórias anteriores
- Story 2.1 preparou:
tvAcrescimoPedidoemMainPedidoFragment(vinculado emonCreateView()) etvAcrescimoemTotalPedidoFragment— ambos prontos para receber valores calculados - Story 1.2 garantiu:
FormaPagamento.getTxAcrescimo()retornadouble(nunca null; NULL no SQLite → 0.0) - Story 2.1 documentou: padrão
vlAcrescimo = 0.0como ponto de expansão explícito nos dois locais deMainPedidoFragmente como0.0hardcoded emTotalPedidoFragment - Padrão de separação UI/background do
MainPedidoFragment.onStart()(Thread +runOnUiThread) não é necessário aqui — cálculo é puramente em memória, sem I/O
Review Findings
- [Review][Defer]
txAcrescimonegativo não guardado — banco de dados do ERP possui checagem para valores negativos, tornando o guard defensivo desnecessário — deferred, ERP validates at source - [Review][Defer]
Global.pedidosem null-check ematualizarResumoPedido()— padrão pré-existente: método já chamaGlobal.pedido.getQtdTotalProduto()etc. sem guard [MainPedidoFragment.java:958] — deferred, pre-existing - [Review][Defer]
Global.pedidosem null-check emTotalPedidoFragment.FillFields()— NPE silenciosa dentro docatch(Exception e){}vazio; pré-existente [TotalPedidoFragment.java:74] — deferred, pre-existing - [Review][Defer] Lógica de cálculo do acréscimo duplicada em
fillFields()eatualizarResumoPedido()sem método auxiliar — padrão DRY violado, pré-existente no projeto [MainPedidoFragment.java:436,975] — deferred, pre-existing - [Review][Defer]
catch (Exception e) {}vazio emTotalPedidoFragment.FillFields()engole qualquer exceção do novo bloco — pré-existente [TotalPedidoFragment.java:99] — deferred, pre-existing - [Review][Defer] Aritmética de ponto flutuante (
double) para valores monetários — padrão projeto-wide pré-existente;Util.formataValorMonetario()já trata formatação [todos os sites] — deferred, pre-existing - [Review][Defer]
codigoLiberacao2()computa o hash de autorização sobretotalGeralsem acréscimo — supervisor autoriza valor menor que o real quando há acréscimo; escopo da Story 2.3 [MainPedidoFragment.java:652] — deferred, pre-existing - [Review][Defer]
validaCampos(): verificação de limite de crédito usagetTotalProduto()excluindo acréscimo — pré-existente, fora do escopo da Story 2.2 [MainPedidoFragment.java:606] — deferred, pre-existing - [Review][Defer]
validaCampos(): check devlPedMinusagetTotalProduto()excluindo acréscimo — pré-existente [MainPedidoFragment.java:617] — deferred, pre-existing - [Review][Defer] Race condition:
listForPagtospreenchido em thread background vs atualização da UI noHandler.post— pré-existente, não introduzido por este diff [MainPedidoFragment.java:193] — deferred, pre-existing - [Review][Defer]
totalGeralcalculado com threshold diferente emfillFields()(≤ STATUS_LIBERADO) vsatualizarResumoPedido()(< STATUS_ENVIADO) paradescontoV— inconsistência pré-existente entre os dois métodos — deferred, pre-existing - [Review][Defer]
FormaPagamentoemGlobal.pedidopode estar stale após sync do servidor —txAcrescimoem memória reflete taxa pré-sync até o usuário navegar da tela — deferred, pre-existing
Dev Agent Record
Agent Model Used
claude-sonnet-4-6 (dev-story workflow)
Debug Log References
Completion Notes List
- Story 2.2 implementada em 2026-04-16.
MainPedidoFragment.java—atualizarResumoPedido(): substituído placeholdervlAcrescimo = 0.0por cálculo realtotalGeral * (txAcrescimo / 100.0)com null-guard emgetFormapag().tvTotalGeralagora exibetotalGeral + vlAcrescimo.MainPedidoFragment.java—fillFields(): mesma substituição aplicada, garantindo que o campo de acréscimo e o total já mostram o valor correto ao carregar o pedido.TotalPedidoFragment.java—FillFields(): substituídoUtil.formataValorMonetario(0.0)hardcoded por cálculo equivalente usando variável localvlTotalGeral.tvTotalGeralatualizado comvlTotalGeral + vlAcrescimo.- Null-guard
if (Global.pedido.getFormapag() != null)aplicado nos 3 pontos —tx_acrescimodefault 0.0 quando sem forma de pagamento (AC3 satisfeito). - Cálculo puramente aritmético em memória, sem I/O — NFR1 < 100ms satisfeito trivialmente (AC4 satisfeito).
- Sem testes automatizados (projeto não possui infraestrutura de testes). Validação é manual via dispositivo/emulador.
- AC1 satisfeito: subtotal × (tx_acrescimo/100) exibido ao selecionar forma com acréscimo.
- AC2 satisfeito: ao trocar para forma sem acréscimo, campo retorna a R$ 0,00 e total retorna ao subtotal.
File List
src/br/com/jcsinformatica/sarandroid/pedido/MainPedidoFragment.javasrc/br/com/jcsinformatica/sarandroid/pedido/TotalPedidoFragment.java