agenda: popover sincroniza com eventos + antecipar nao reusa cancelled
Dois bugs descobertos no ciclo C12 antecipar -> revogar -> reantecipar:
1) confirmAnteciparPagamento reusava record cancelled:
Quando user revogava (vira cancelled) e antecipava de novo,
o existRec query pegava o cancelled e UPDATE-ava pra paid no
MESMO record id. Resultado: notes mantinham historico
"Cancelada via reversao" + "Antecipacao revogada" + record
reativo como paid, confuso pra audit trail. Fix: filtrar
.neq('status', 'cancelled') na busca de existRec — agora a
re-antecipacao via RPC cria record fresh.
2) Popover snapshot stale (pendencia documentada em
project_melissa_popover_snapshot, antecipada pra agora):
eventoSelecionado.value era snapshot do clique e nao acompanhava
updates do _paymentStateMap pos M.refetch. User antecipava, o
record paid era criado, mas o popover continuava com paymentState
antigo -> botao continuava "Antecipar pagamento" em vez de
alternar pra "Revogar pagamento". Fix: watch em M.eventos sincroniza
eventoSelecionado com a versao fresh quando id bate. flush:'post'
pra rodar apos o computed reagir.
Como o popover agora atualiza in-place, removido fecharEvento() de
confirmAnteciparPagamento e onRevogarAntecipacao — o user pode ver
o botao alternar live em vez de precisar reabrir o popover.
Cleanup do estado do Andre: deletado record orfa 3a4c79e0 pra reset
do teste C12.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -665,6 +665,21 @@ function fecharEvento() {
|
|||||||
eventoBusy.value = false;
|
eventoBusy.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mantém eventoSelecionado em sincronia com a lista reativa M.eventos.
|
||||||
|
// Sem isso, eventoSelecionado.value é snapshot do clique e não acompanha
|
||||||
|
// updates do _paymentStateMap pós refetch (caso típico: revogar/antecipar
|
||||||
|
// pagamento — record muda mas popover continuava mostrando estado antigo).
|
||||||
|
// Watch dispara apenas quando o ev correspondente aparece novo no eventos
|
||||||
|
// computed (paymentState atualizado pelo bulk-load).
|
||||||
|
watch(() => M.eventos.value, (novos) => {
|
||||||
|
const sel = eventoSelecionado.value;
|
||||||
|
if (!sel?.id) return;
|
||||||
|
const fresh = novos.find((e) => e.id === sel.id);
|
||||||
|
if (fresh && fresh !== sel) {
|
||||||
|
eventoSelecionado.value = fresh;
|
||||||
|
}
|
||||||
|
}, { flush: 'post' });
|
||||||
|
|
||||||
// ── Actions do MelissaEventoPanel ──────────────────────────────
|
// ── Actions do MelissaEventoPanel ──────────────────────────────
|
||||||
// Fase 5 (2026-05-14): TODOS os status (realizado/faltou/cancelado/etc)
|
// Fase 5 (2026-05-14): TODOS os status (realizado/faltou/cancelado/etc)
|
||||||
// passam por M.onUpdateSeriesEvent — que abre o AgendaStatusChangeConfirmDialog
|
// passam por M.onUpdateSeriesEvent — que abre o AgendaStatusChangeConfirmDialog
|
||||||
@@ -811,12 +826,17 @@ async function confirmAnteciparPagamento() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Verifica se já tem financial_record vinculado
|
// 2) Verifica se já tem financial_record vinculado.
|
||||||
|
// IMPORTANTE: filtra cancelled — caso típico após revogar a antecipação
|
||||||
|
// (record vira cancelled) e user re-antecipa. Sem o filtro, o handler
|
||||||
|
// reusava o record cancelled atualizando pra paid, mantendo notes
|
||||||
|
// da revogação no audit trail (confuso).
|
||||||
const { data: existRec } = await supabase
|
const { data: existRec } = await supabase
|
||||||
.from('financial_records')
|
.from('financial_records')
|
||||||
.select('id, status')
|
.select('id, status')
|
||||||
.eq('agenda_evento_id', eventoId)
|
.eq('agenda_evento_id', eventoId)
|
||||||
.is('deleted_at', null)
|
.is('deleted_at', null)
|
||||||
|
.neq('status', 'cancelled')
|
||||||
.order('created_at', { ascending: false })
|
.order('created_at', { ascending: false })
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
@@ -869,9 +889,10 @@ async function confirmAnteciparPagamento() {
|
|||||||
life: 4000
|
life: 4000
|
||||||
});
|
});
|
||||||
anteciparDialogOpen.value = false;
|
anteciparDialogOpen.value = false;
|
||||||
M.refetch();
|
await M.refetch();
|
||||||
refetchEventosHoje();
|
refetchEventosHoje();
|
||||||
fecharEvento();
|
// Não fecha o popover — watch em eventos sincroniza o ev pro novo
|
||||||
|
// estado (paymentState='paid' agora). Botão alterna pra "Revogar".
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao antecipar pagamento.', life: 5000 });
|
toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao antecipar pagamento.', life: 5000 });
|
||||||
} finally {
|
} finally {
|
||||||
@@ -943,9 +964,10 @@ async function onRevogarAntecipacao() {
|
|||||||
detail: `Cobrança de R$ ${Number(paidRec.final_amount || paidRec.amount || 0).toFixed(2).replace('.', ',')} cancelada.`,
|
detail: `Cobrança de R$ ${Number(paidRec.final_amount || paidRec.amount || 0).toFixed(2).replace('.', ',')} cancelada.`,
|
||||||
life: 4000
|
life: 4000
|
||||||
});
|
});
|
||||||
M.refetch();
|
await M.refetch();
|
||||||
refetchEventosHoje();
|
refetchEventosHoje();
|
||||||
fecharEvento();
|
// Não fecha popover — watch em eventos sincroniza paymentState='none'.
|
||||||
|
// Botão alterna de volta pra "Antecipar pagamento".
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao revogar antecipação.', life: 5000 });
|
toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao revogar antecipação.', life: 5000 });
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user