diff --git a/database-novo/migrations/20260521000008_recibo_uses_terapeuta_registro.sql b/database-novo/migrations/20260521000008_recibo_uses_terapeuta_registro.sql new file mode 100644 index 0000000..7387e63 --- /dev/null +++ b/database-novo/migrations/20260521000008_recibo_uses_terapeuta_registro.sql @@ -0,0 +1,35 @@ +-- ============================================================================ +-- ROADMAP #1.4 #14 — Recibo profissional usa terapeuta_registro genérico +-- ---------------------------------------------------------------------------- +-- O template recibo_pagamento (seed_015) usa "Psicólogo(a) — CRP {{terapeuta_crp}}". +-- Como agora suportamos múltiplos conselhos (CRP/CRM/CRFa/CREFITO/CRESS/CRN/RMS) +-- via #5 (migration 20260521000003), o recibo precisa ser CFP-agnóstico. +-- +-- Esta migration substitui no recibo_pagamento: +-- "Psicólogo(a) — CRP {{terapeuta_crp}}" → "{{terapeuta_registro}}" +-- e atualiza variaveis[] removendo terapeuta_crp + adicionando terapeuta_registro. +-- +-- {{terapeuta_registro}} é auto-formatado server-side como "CRP 12345/SP", +-- "CRM 12345/SP" etc, então não precisa de "Psicólogo(a) —" hardcoded. +-- ============================================================================ + +BEGIN; + +UPDATE public.document_templates +SET corpo_html = REPLACE( + corpo_html, + 'Psicólogo(a) — CRP {{terapeuta_crp}}', + '{{terapeuta_registro}}' +), +variaveis = ARRAY( + SELECT DISTINCT v FROM ( + SELECT unnest(variaveis) v + UNION ALL + SELECT 'terapeuta_registro' + ) sub + WHERE v <> 'terapeuta_crp' +), +updated_at = now() +WHERE tipo = 'recibo_pagamento' AND is_global = true; + +COMMIT; diff --git a/src/components/agenda/AgendaEventoFinanceiroPanel.vue b/src/components/agenda/AgendaEventoFinanceiroPanel.vue index 189e557..9066465 100644 --- a/src/components/agenda/AgendaEventoFinanceiroPanel.vue +++ b/src/components/agenda/AgendaEventoFinanceiroPanel.vue @@ -36,6 +36,7 @@ import { useConfirm } from 'primevue/useconfirm'; import { supabase } from '@/lib/supabase/client'; import { useAgendaFinanceiro } from '@/composables/useAgendaFinanceiro'; +import { emitirReciboParaSessao } from '@/services/DocumentGenerate.service'; // ── props / emits ───────────────────────────────────────────────────────────── const props = defineProps({ @@ -56,6 +57,7 @@ const { gerarCobrancaManual, loading: finLoading, error: finError } = useAgendaF const record = ref(null); // financial_record vinculado const fetching = ref(false); const generating = ref(false); +const emittingRecibo = ref(false); // ── opções de método de pagamento ───────────────────────────────────────────── const PAYMENT_METHODS = [ @@ -224,6 +226,27 @@ function requestCancel() { } }); } + +// ── Emitir recibo PDF da sessão ───────────────────────────────────────────── +// Gera, salva (Storage + documents/document_generated) e baixa um recibo +// pré-preenchido com paciente/sessão/valor/forma de pagamento + registro +// profissional do terapeuta (CRP/CRM/CRFa etc — auto-formatado). +async function onEmitirRecibo() { + if (emittingRecibo.value) return; + emittingRecibo.value = true; + try { + await emitirReciboParaSessao(props.evento.id, { + patientId: props.evento.patient_id || props.evento.paciente_id, + valor: record.value?.final_amount ?? record.value?.amount ?? props.evento.price, + formaPagamento: paymentLabel(record.value?.payment_method) + }); + toast.add({ severity: 'success', summary: 'Recibo emitido', detail: 'PDF baixado e salvo nos documentos do paciente.', life: 3000 }); + } catch (e) { + toast.add({ severity: 'error', summary: 'Erro ao emitir recibo', detail: e?.message || 'Tente novamente.', life: 4500 }); + } finally { + emittingRecibo.value = false; + } +}