agenda: revogar antecipacao de pagamento

UX gap descoberto durante teste C12: apos antecipar pagamento,
nao havia caminho via popover pra desfazer caso user tenha
errado (paciente nao pagou, errou o valor, etc).

Implementacao:
- Botao "Antecipar pagamento" agora alterna pra "Revogar
  pagamento" (vermelho, --danger) quando isAntecipacaoAtiva
  (status=agendado + paymentState=paid)
- Handler onRevogarAntecipacao em MelissaLayout: ConfirmDialog
  vermelho + cancela record paid + nota de auditoria em notes
  ("[YYYY-MM-DD] Antecipacao revogada em ...") + refetch
- Apos revogar, botao volta pra "Antecipar pagamento" — user
  pode antecipar de novo com valor/metodo corretos

Limites: so disponivel em status='agendado'. Apos Realizada o
paid representa pagamento real da sessao realizada, nao
antecipacao — estorno deve ir pelo /financeiro.

Sobre "Usar" desaparecer apos antecipar (questao do user): comportamento
correto. "Usar" cria record+consome saldo — duplicaria com paid
existente. Apos antecipar, fluxo correto e clicar Realizada (que
detecta paid pre-existente via fix anterior 00c4168).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-20 14:28:04 -03:00
parent 00c4168393
commit 272c804335
2 changed files with 94 additions and 0 deletions
+75
View File
@@ -879,6 +879,80 @@ async function confirmAnteciparPagamento() {
}
}
// Revogar antecipação de pagamento (C12): desfaz o `onAnteciparPagamento`.
// Cancela o record paid + nota de auditoria em notes. Só disponível pra
// sessão em status='agendado' (após Realizada o paid vira pagamento normal
// e estorno é via /financeiro).
async function onRevogarAntecipacao() {
const ev = eventoSelecionado.value;
if (!ev?.id || eventoBusy.value) return;
const isVirtualId = typeof ev.id === 'string' && ev.id.startsWith('rec::');
if (isVirtualId) {
toast.add({ severity: 'warn', summary: 'Sessão virtual', detail: 'Sessão sem antecipação ativa.', life: 3000 });
return;
}
// Confirma com user — paid é sensível
const ok = await new Promise((resolve) => {
confirm.require({
message: 'Revogar o pagamento antecipado desta sessão? O lançamento financeiro será cancelado e poderá antecipar de novo.',
header: 'Revogar antecipação?',
icon: 'pi pi-exclamation-triangle',
acceptLabel: 'Revogar pagamento',
rejectLabel: 'Cancelar',
acceptClass: 'p-button-danger',
accept: () => resolve(true),
reject: () => resolve(false),
onHide: () => resolve(false)
});
});
if (!ok) return;
eventoBusy.value = true;
try {
// Acha o paid record vinculado
const { data: paidRec, error: fetchErr } = await supabase
.from('financial_records')
.select('id, notes, payment_method, final_amount, amount')
.eq('agenda_evento_id', ev.id)
.eq('status', 'paid')
.order('paid_at', { ascending: false })
.limit(1)
.maybeSingle();
if (fetchErr) throw fetchErr;
if (!paidRec?.id) {
toast.add({ severity: 'info', summary: 'Nada a revogar', detail: 'Esta sessão não tem pagamento antecipado.', life: 3500 });
return;
}
const today = new Date().toISOString().slice(0, 10);
const reason = `Antecipação revogada em ${today}`;
const noteEntry = `[${today}] ${reason}`;
const noteText = paidRec.notes ? `${paidRec.notes}\n${noteEntry}` : noteEntry;
const { error: cancelErr } = await supabase
.from('financial_records')
.update({
status: 'cancelled',
notes: noteText,
updated_at: new Date().toISOString()
})
.eq('id', paidRec.id);
if (cancelErr) throw cancelErr;
toast.add({
severity: 'success',
summary: 'Antecipação revogada',
detail: `Cobrança de R$ ${Number(paidRec.final_amount || paidRec.amount || 0).toFixed(2).replace('.', ',')} cancelada.`,
life: 4000
});
M.refetch();
refetchEventosHoje();
fecharEvento();
} catch (e) {
toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao revogar antecipação.', life: 5000 });
} finally {
eventoBusy.value = false;
}
}
async function onVerLancamentos() {
const ev = eventoSelecionado.value;
if (!ev?.id) return;
@@ -2504,6 +2578,7 @@ function onKeydown(e) {
@revogar-sessao="onRevogarSessao"
@ver-lancamentos="onVerLancamentos"
@antecipar-pagamento="onAnteciparPagamento"
@revogar-antecipacao="onRevogarAntecipacao"
@edit-paciente="onEditPaciente"
@abrir-prontuario="onAbrirProntuario"
@whatsapp="onWhatsapp"