0010 — Visibilidade de pagamento: parcial travado e cancelamento pós-import¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-08-20 · Decidido em: 2026-08-20
Contexto¶
Investigação sobre o banco real (db_maxsul, janela REST de 8 dias, ~500 pedidos pagos) expôs dois
pontos cegos no fluxo PIED → X-Adm:
- Parcial que trava. Pedido com pagamento dividido (ex.: Pix pago + Cartão pendente) fica em
payment.status = partial. O gate de envio dispara só emreceived, então o parcial nunca é enviado — e some do radar se o saldo não fecha. Dados: 6 parciais/8 dias; 4 viraramreceivedsozinhos em ~1 dia; 2 travaram (ex.:260065499, parado +1d19h). Nenhum parcial cancelou. - Cancelamento pós-importação. Pedido pago, enviado e importado no X-Adm (
status = CONFIRMADO) depois cancelado na PIED (payment.status → cancelled). A integração não propaga — o pedido segue ativo e faturável no X-Adm sem ninguém saber. Caso real:260070866(requested → received → [CONFIRMADO] → cancelled). 1 caso em 8 dias / ~500 pagos; os outros 15 cancelamentos nunca pagaram → corretamente não importados → sem alerta (zero falso-positivo).
Decisão¶
Envio segue received-only (decisão do cliente, confirmada com dados). Comparação do MESMO
pedido em partial × received mostrou os campos que dirigem a NF (finalValue, originalValue,
invoice.serviceTotal, freight.price, produtos) idênticos — enviar parcial não corrige valor
nenhum; o único risco é faturar um pedido não-quitado. Então parcial é tratado por visibilidade,
não por envio.
Duas adições (spec .ia/007, migration V8), atrás do toggle pied.integracao.habilitada:
- A — Parcial travado: coluna
pied_pedido.parcial_desde(carimbo da transição →partial, espelho dopago_em). Home e detalhe mostram aviso quando o pedido está empartialhá mais de 5 dias corridos. Regra pura emAvisosPagamento(Java, testável). - B — Cancelamento pós-import: coluna
pied_pedido.cancelado_pied_em(set-once, na transição paracancelledde um pedidoCONFIRMADO). Ao detectar a transição, um e-mail aos destinatários cadastrados (reusaAlertaService/Resend, best-effort), com orientação de ação manual no X-Adm. Home e detalhe mostram aviso. O X-Adm não é tocado (o cancelamento é manual, é o ponto).
Detecção do e-mail em Java no NormalizadorService (o mesclar já carrega o estado anterior):
dispara na transição em que cancelado_pied_em vai de NULL para setado — unicidade do e-mail =
unicidade do set-once da coluna (robusto a cancelled → received → cancelled; sem flag extra).
Consequências¶
- Status permanece
CONFIRMADOno cancelamento pós-import — o pedido está importado; o aviso vem da coluna, não de um estado novo (não mexe emStatusBucket/timeline). parcial_desde/cancelado_pied_emnão retroalimentam histórico (nascem NULL). No deploy, um pedido jáCONFIRMADO+cancelled(ex.:260070866) não dispara e-mail retroativo — a transição já passou.- Cancelamento durante a janela
ENVIADO(enviado, ainda não reconciliado) não alerta — sóCONFIRMADO. Janela ~1min (reconciliação); aceito.
Alternativas consideradas¶
- Enviar parcial ao X-Adm: rejeitada — não melhora o valor da NF (idêntico ao
received) e arrisca faturar saldo em aberto; os 2 travados são exatamente os arriscados. - Novo estado
CANCELADO_PIED: rejeitada — exigiria mapear bucket/timeline; a coluna + aviso resolve com menos superfície. - E-mail de parcial travado: rejeitada — parcial é ~1% e raro; e-mail viraria ruído. Fica só o aviso no painel (o operador já vive nessa tela).
- Dedup do e-mail por
payment_status_anterior/ colunaalerta_enviado+ job: rejeitada — amarrar ao set-once da própria coluna é mais simples e sem re-alerta em re-cancelamento.