diff --git a/src/layout/melissa/composables/useMelissaAgenda.js b/src/layout/melissa/composables/useMelissaAgenda.js index 0ca54e0..1302027 100644 --- a/src/layout/melissa/composables/useMelissaAgenda.js +++ b/src/layout/melissa/composables/useMelissaAgenda.js @@ -1442,13 +1442,14 @@ function _buildHandlers(deps) { const tasks = []; // 1) Consumir saldo (pacote saldo + faltou/cancelado + decisão sim) + // ⚠ billing_contracts NÃO tem coluna updated_at — passar esse campo + // causa "column does not exist" silenciosamente em Promise.allSettled. if (decision.consumeSaldo && ctx.billingContract?.id) { tasks.push( supabase .from('billing_contracts') .update({ - sessions_used: (ctx.billingContract.sessions_used ?? 0) + 1, - updated_at: new Date().toISOString() + sessions_used: (ctx.billingContract.sessions_used ?? 0) + 1 }) .eq('id', ctx.billingContract.id) ); @@ -1529,31 +1530,59 @@ function _buildHandlers(deps) { ); } - // 4) Realizado em pacote saldo: cria cobrança individual + incrementa sessions_used + // 4) Realizado em pacote saldo: amarra contract + cria cobrança + incrementa saldo + // Refatorado pra usar AWAITS SEQUENCIAIS (igual onUsarSessao do MelissaLayout). + // Antes era Promise.allSettled paralelo que escondia falhas silenciosas + // — durante teste C11/A o sessions_used não incrementava + agenda_evento + // ficava sem billing_contract_id. Ambos os updates não rodavam mas o + // toast warn não aparecia. Agora cada step tem error explícito. if (decision.generatePackageCharge && ctx.billingContract?.id) { - const amount = Number(row.price ?? 0); + const amount = Number(row.price ?? (ctx.billingContract.total_sessions > 0 ? (Number(ctx.billingContract.package_price) || 0) / ctx.billingContract.total_sessions : 0)); const dueIso = row.inicio_em ? new Date(row.inicio_em).toISOString().slice(0, 10) : new Date().toISOString().slice(0, 10); - // Cria record - tasks.push( - supabase.rpc('create_financial_record_for_session', { + + // 4a) Amarra agenda_evento ao contrato. Pra virtual recém-materializada, + // _applyStatusUpdateOnly criou o evento SEM billing_contract_id — + // precisa update separado aqui. + try { + const { error: linkErr } = await supabase.from('agenda_eventos').update({ billing_contract_id: ctx.billingContract.id, updated_at: new Date().toISOString() }).eq('id', eventoId); + if (linkErr) throw linkErr; + } catch (e) { + console.error('[Fase5] erro amarrando billing_contract_id:', e?.message); + toast.add({ severity: 'warn', summary: 'Pacote — amarração', detail: e?.message || 'Falha ao amarrar sessão ao pacote', life: 5000 }); + } + + // 4b) Cria financial_record (RPC tolera idempotência) + try { + const { error: rpcErr } = await supabase.rpc('create_financial_record_for_session', { p_tenant_id: tenantId, p_owner_id: uid, p_patient_id: patientId, p_agenda_evento_id: eventoId, p_amount: amount, p_due_date: dueIso - }) - ); - // Incrementa saldo usado - tasks.push( - supabase - .from('billing_contracts') - .update({ - sessions_used: (ctx.billingContract.sessions_used ?? 0) + 1, - updated_at: new Date().toISOString() - }) - .eq('id', ctx.billingContract.id) - ); + }); + if (rpcErr) throw rpcErr; + } catch (e) { + console.error('[Fase5] erro RPC create_financial_record_for_session:', e?.message); + toast.add({ severity: 'error', summary: 'Cobrança', detail: e?.message || 'Falha ao gerar cobrança do pacote', life: 7000 }); + } + + // 4c) Incrementa sessions_used + completa contract se atingir total + // ⚠ billing_contracts NÃO tem coluna updated_at — passar esse + // campo causa "column does not exist" silenciosamente em + // Promise.allSettled (era o root cause do saldo não incrementar). + try { + const newUsed = (ctx.billingContract.sessions_used ?? 0) + 1; + const patchContract = { sessions_used: newUsed }; + if (newUsed >= (ctx.billingContract.total_sessions ?? 0)) { + patchContract.status = 'completed'; + } + const { error: incErr } = await supabase.from('billing_contracts').update(patchContract).eq('id', ctx.billingContract.id); + if (incErr) throw incErr; + } catch (e) { + console.error('[Fase5] erro incrementando sessions_used:', e?.message); + toast.add({ severity: 'warn', summary: 'Saldo do pacote', detail: e?.message || 'Falha ao atualizar saldo do pacote', life: 6000 }); + } } // Roda tudo em paralelo (falha parcial é tolerável — toast warn)