Skip to main content

Code Review — Task 01 (196866) — [Front] Novo layout do card de produto

Branch: feat/196869_upsell_status_pedido
Base: develop (merge-base cc743fd8)
Data: 30/06/2026
Escopo: 15 arquivos (+1418 / −39 linhas), 2 commits vs develop


Resumo

A branch entrega o novo card de produto no detalhe do status do pedido (CartStatusProductCardNew), com DTO de apresentação, mapper de descontos alinhado aos RF 4–8, novos campos em ProductCartDetail e modelo CartItemRecommendation, além de bateria de testes focada no mapper e no widget. A arquitetura separa regra (ProductCardDiscountMapper) de UI (ProductCardDTO + card), o que facilita manutenção.

Após triage (grilling 30/06/2026), Issues 2–4 eram falsos positivos dado o contrato da API (discountOrigin substitui discountMarkdown no cart detail). Issue 1 corrigida com toApiString(). Lacunas de teste em DTO, mapper e widget resolvidas (Issues 7, 9, 10). Nits 13–14 corrigidos.

Testes executados na revisão inicial: 36 testes (4 arquivos).
Testes após correções: flutter test em 5 arquivos — 43 testes, todos passando.


Comparação de cobertura de testes (develop vs branch tarefa)

Método: flutter test --coverage com conjuntos comparáveis ao que existe em cada branch.

ComandoBranch
test/models/product/product_cart_detail_test.dartdevelop
Os 4 testes novos (cart_item_recommendation, product_cart_detail_new_fields, product_card_discount_mapper, cart_status_product_card_new)feat/196869_upsell_status_pedido

Cobertura de linhas (LCOV) apenas nos arquivos lib/ alterados ou introduzidos nesta entrega:

ArquivodevelopBranch tarefaΔ
lib/models/cart/cart_item_recommendation.dartN/A (arquivo inexistente)89,7% (26/29)
lib/models/product/product_cart_detail.dart90,9% (30/33)50,0% (20/40)−40,9 pp*
lib/screens/cart_status/cart_status_detail_screen.dart0,8% (2/263)0,8% (2/266)≈0
lib/screens/cart_status/models/product_card_dto.dartN/A54,8% (17/31)
lib/screens/cart_status/utils/product_card_discount_mapper.dartN/A100,0% (32/32)
lib/screens/cart_status/widgets/cart_status_product_card_new.dartN/A96,2% (50/52)
lib/shared/enum/cart_item_discount_origin.dartN/A100,0% (4/4)
lib/shared/enum/discount_type.dartN/A60,0% (3/5)
lib/shared/utils/logger_utils.dart37,5% (3/8)66,7% (4/6)+29,2 pp**
lib/theme_widgets/banner/zz_confirmation_banner.dartN/A100,0% (12/12)
Total agregado do escopo11,5% (35/304)35,6% (170/477)+24,1 pp

* Na branch tarefa o modelo ganhou linhas novas (discountOrigin, fromRecommendation, hasEmployeeDiscount); o teste legado em develop não cobre esses caminhos — o teste dedicado product_cart_detail_new_fields_test.dart cobre o parse, mas não todas as linhas do toJson/roundtrip.

** Refatoração do logger alterou o número de linhas instrumentadas; a comparação direta é indicativa, não equivalente funcional.

Leitura: a entrega melhora cobertura no núcleo da feature (mapper 100%, card ~96%). product_card_dto e integração em cart_status_detail_screen ficam abaixo do ideal; em develop não havia testes de cart_status para este layout.


Achados

Issue 1 — Severity: bug

  • Arquivo: lib/models/product/product_cart_detail.dart:95
  • Descrição: toJson usa discountOrigin.name (ex.: markdown, manual), enquanto CartItemDiscountOriginParser.fromJson espera literais da API (Markdown, Manual, Both). Roundtrip fromJson → toJson → fromJson perde a origem correta.
  • Sugestão: Serializar com os mesmos literais da API (ex.: método toApiString()) e adicionar teste de roundtrip em product_cart_detail_new_fields_test.dart.
  • Status: resolved — toApiString() em cart_item_discount_origin.dart; roundtrip em product_cart_detail_new_fields_test.dart

Issue 2 — Severity: bug

  • Arquivo: lib/screens/cart_status/utils/product_card_discount_mapper.dart:31
  • Descrição: Para discountOrigin == both, o tipo vira apenas manual ou funcionario e o valor exibido usa discount/discountValue. O card antigo (cart_status_product_card.dart) ainda exibia Remarcação via discountMarkdown em linha separada. Pedidos com markdown + desconto manual podem mostrar valor incompleto.
  • Sugestão: Validar RF 5 com negócio; se ambos coexistem, compor exibição (ex.: considerar discountMarkdown ou fullPrice - price além do desconto manual).
  • Status: wontfix — RF-05.7 correto; Both exibe manual/funcionario via discount/discountValue; linha Remarcação removida por RF-02.4

Issue 3 — Severity: bug

  • Arquivo: lib/screens/cart_status/utils/product_card_discount_mapper.dart:26
  • Descrição: Com discountOrigin == none (ou campo ausente) e discountMarkdown > 0, o novo fluxo retorna DiscountType.none e R$ 0,00. O card legado exibia remarcação nesse cenário — regressão para API/pedidos sem o campo novo.
  • Sugestão: Fallback no mapper: se discountOrigin == none e discountMarkdown > 0, tratar como sale (ou usar discountMarkdown no cálculo).
  • Status: wontfix — discountMarkdown não vem da API de cart detail (cart-detail.json); markdown via discountOrigin + fullPrice/price

Issue 4 — Severity: bug

  • Arquivo: lib/screens/cart_status/utils/product_card_discount_mapper.dart:72
  • Descrição: Para manual/funcionario, só discount == 1 ou 2 calculam valor; outros códigos deixam calculatedValue em 0 sem tratamento explícito, podendo exibir rótulo de desconto com valor zerado mesmo com price < fullPrice.
  • Sugestão: Tratar discount inválido com fallback documentado ou teste que fixe o comportamento esperado.
  • Status: wontfix — API garante discount2; R$ 0,00 é comportamento defensivo (RF-04.4)

Issue 5 — Severity: suggestion

  • Arquivo: lib/shared/utils/logger_utils.dart:4
  • Descrição: Refatoração do logger (singleton, remoção de printTime) não está ligada ao layout do card; aumenta superfície de revisão e risco colateral.
  • Sugestão: Mover para commit/PR separado ou reverter nesta branch.
  • Status: wontfix — refatoração mantida (singleton, sem printTime)

Issue 6 — Severity: suggestion

  • Arquivo: lib/screens/cart_status/widgets/cart_status_product_card.dart:99
  • Descrição: Widget legado permanece após troca em cart_status_detail_screen, com lógica de remarcação que o novo card não replica integralmente.
  • Sugestão: Deprecar/remover após validação de paridade ou documentar coexistência temporária.
  • Status: wontfix — legado removido; único uso era _ContentProducts; atualizar RF-01 nos docs (follow-up FU-04)

Issue 7 — Severity: suggestion

  • Arquivo: lib/screens/cart_status/models/product_card_dto.dart:31
  • Descrição: Sem testes para fromOrderItem e fromRecommended, que montam labels, showRecommendationTag, valor e precoFinal.
  • Sugestão: Criar test/screens/cart_status/models/product_card_dto_test.dart.
  • Status: resolved — test/screens/cart_status/models/product_card_dto_test.dart criado

Issue 8 — Severity: suggestion

  • Arquivo: lib/theme_widgets/banner/zz_confirmation_banner.dart:6
  • Descrição: Banner exportado no design system e usado no card, sem teste de widget dedicado (só indireto no card).
  • Sugestão: Teste mínimo de renderização e ícone customizado.
  • Status: follow-up — teste dedicado de ZzConfirmationBanner (FU-01)

Issue 9 — Severity: suggestion

  • Arquivo: test/screens/cart_status/widgets/cart_status_product_card_new_test.dart:35
  • Descrição: Cobertura limitada a orderItem e presença de textos; não exercita recommended, tipos sale/funcionario nem valores monetários formatados.
  • Sugestão: Ampliar cenários e asserts em - R$ … / preços finais.
  • Status: resolved — cenários recommended, sale, funcionario e valores R$ adicionados

Issue 10 — Severity: suggestion

  • Arquivo: test/screens/cart_status/utils/product_card_discount_mapper_test.dart
  • Descrição: Falta caso explícito para DiscountType.funcionario em formatDiscountDisplay e para RF 7.5 (prioridade discount > 0 sobre price < fullPrice em recomendados).
  • Sugestão: Adicionar os dois testes.
  • Status: resolved — testes funcionario em formatDiscountDisplay e RF 7.5 adicionados

Issue 11 — Severity: suggestion

  • Arquivo: lib/screens/cart_status/cart_status_detail_screen.dart:544
  • Descrição: Integração na lista de produtos (padding, uso do novo card) sem teste de widget/golden.
  • Sugestão: Teste com productCartDetails mockados em _ContentProducts.
  • Status: follow-up — widget test de _ContentProducts (FU-02)

Issue 12 — Severity: nit

  • Arquivo: lib/models/cart/cart_item_recommendation.dart:7
  • Descrição: Campos mutáveis, em contraste com DTOs imutáveis (ProductCardDTO).
  • Sugestão: Tornar final se o modelo for somente leitura após parse.
  • Status: wontfix — mutabilidade alinhada ao padrão do projeto (ProductCartDetail)

Issue 13 — Severity: nit

  • Arquivo: lib/theme_widgets/banner/zz_confirmation_banner.dart:20
  • Descrição: padding horizontal 0 e comentário //12, em ZZFontSize.xxxs podem afetar alinhamento visual.
  • Sugestão: Remover comentário e alinhar padding ao design.
  • Status: resolved — padding horizontal 12; comentário removido

Issue 14 — Severity: nit

  • Arquivo: test/screens/cart_status/widgets/cart_status_product_card_new_test.dart:49
  • Descrição: find.text('1') é frágil (colisão com outros widgets); arquivo sem newline final.
  • Sugestão: Buscar quantidade no contexto da linha "Qtd."; adicionar newline EOF.
  • Status: resolved — quantityInQtdRow() no contexto de "Qtd: "; newline EOF

Issue 15 — Severity: nit

  • Arquivo: lib/screens/cart_status/widgets/cart_status_product_card_new.dart
  • Descrição: Factories orderItem/recommended não expõem Key opcional para itens em ListView.
  • Sugestão: Repassar Key? key ao construtor.
  • Status: follow-up — Key? nas factories (task 196865, FU-03)

Contagem de issues (pós-triage)

StatusQuantidadeIssues
resolved61, 7, 9, 10, 13, 14
wontfix62, 3, 4, 5, 6, 12
follow-up38, 11, 15

Veredito: aprovável para merge. Correções obrigatórias aplicadas (Issue 1 + testes 7/9/10 + nits 13/14). Follow-ups: FU-01 (banner test), FU-02 (screen test), FU-03 (Key?), FU-04 (atualizar RF-01 nos docs).