agenda: C12 prep — detectar paid pre-existente em pacote saldo realizada

Preparacao pra teste C12 (antecipar pagamento). Fluxo:
1. User clica "Antecipar pagamento" em virtual futura -> cria
   record paid R$ X sem consumir saldo
2. Depois marca a sessao como Realizada -> dialog deve detectar
   o paid + so consumir saldo (NAO criar record novo, evitar
   duplicidade)

Sem esse fix, marcar Realizada apos antecipar abriria o dialog
"Gerar cobranca?" com default true, gerando record novo duplicado.

Implementacao:
- _loadStatusChangeContext: carrega ctx.existingPaidRecord (qualquer
  paid linkado ao evento, n=1)
- Dialog: nova prop existingPaidRecord + computed showAlreadyPaid
  (substitui showCobrancaPacote quando paid existe)
- Template: bloco "Sessao ja paga via antecipacao" com info do
  pagamento + preview do consumo de saldo
- _applyStatusDecisions: novo branch 4-pre roda ANTES do generatePackageCharge:
  se realizado+pacote saldo+paid existe, roda tasks pendentes (1b
  amarra) + incrementa saldo sem criar record. Return cedo.

Backfill: Andre 10/06 voltou pra agendado + saldo 2/4 (estado limpo
pra testar C12 com a sessao 10/06 antecipando).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-20 12:28:19 -03:00
parent 9ead3fdc42
commit 00c4168393
2 changed files with 85 additions and 2 deletions
@@ -49,6 +49,9 @@ const props = defineProps({
billingContractStyle: { type: String, default: null }, // 'upfront' | 'saldo' | null
// Quando avulsa+pendente e novoStatus='realizado': financial_record relacionado
pendingRecord: { type: Object, default: null },
// Quando pacote saldo + realizado + record paid pré-existente (C12 antecipado):
// dialog não oferece "Gerar cobrança" — só confirma consumo de saldo.
existingPaidRecord: { type: Object, default: null },
// Preço da sessão (pra calcular multa percentual e cobrança de pacote saldo)
sessionPrice: { type: Number, default: 0 },
// Reverse transition (novoStatus='agendado'): artefatos a desfazer.
@@ -135,8 +138,11 @@ const showSaldoBlock = computed(() => isFaltouOrCancelado.value && isPacoteSaldo
// Mostrar bloco "registrar pagamento": realizado + avulsa pendente
const showRegistrarPagto = computed(() => isRealizado.value && isAvulsa.value && props.pendingRecord && props.pendingRecord.status === 'pending');
// Mostrar bloco "cobrança no pacote": realizado + pacote saldo
const showCobrancaPacote = computed(() => isRealizado.value && isPacoteSaldo.value);
// Mostrar bloco "cobrança no pacote": realizado + pacote saldo + SEM paid pré-existente
// (se já tem paid via antecipação, mostra o bloco "já pago" em vez deste)
const showCobrancaPacote = computed(() => isRealizado.value && isPacoteSaldo.value && !props.existingPaidRecord);
// Mostrar bloco "já paga via antecipação": realizado + pacote saldo + paid pré-existente
const showAlreadyPaid = computed(() => isRealizado.value && isPacoteSaldo.value && !!props.existingPaidRecord);
// ─── Header ────────────────────────────────────────────────────────────
const headerTitle = computed(() => {
@@ -443,6 +449,23 @@ function onCancel() {
</div>
</div>
<!-- Bloco "JÁ PAGA via antecipação" (C12 fluxo de retorno) -->
<div v-if="showAlreadyPaid" class="asccd-block">
<div class="asccd-block__title">
<i class="pi pi-check-circle" />
Sessão paga via antecipação
</div>
<div class="asccd-info">
<i class="pi pi-info-circle" />
<div>
Cobrança de <b>R$ {{ _fmtBRL(existingPaidRecord.final_amount || existingPaidRecord.amount) }}</b>
foi registrada como paga ({{ existingPaidRecord.payment_method || 'método não definido' }}).
Marcar como Realizada vai <b>consumir 1 sessão do saldo</b>
({{ billingContract?.sessions_used ?? 0 }} {{ (billingContract?.sessions_used ?? 0) + 1 }}/{{ billingContract?.total_sessions ?? '?' }}).
</div>
</div>
</div>
<!-- Bloco COBRANÇA NO PACOTE (realizado + pacote saldo) -->
<div v-if="showCobrancaPacote" class="asccd-block">
<div class="asccd-block__title">