diff --git a/Obsidian/Brain/log.md b/Obsidian/Brain/log.md index 63c4b19..b1b85f7 100644 --- a/Obsidian/Brain/log.md +++ b/Obsidian/Brain/log.md @@ -1282,3 +1282,39 @@ channel factory). Por ora, terapeuta envia link manualmente. PROXIMO: outras 5 secoes do ROADMAP Fase 1 (Asaas Fase B bloqueada, UX §1.3, Fiscal §1.4, Qualidade §1.5). + +## [2026-05-21 evening] session | ROADMAP #14 Recibo profissional PDF +Touched: none (durable em development/02-auditoria/PADRONIZACAO.md + memoria) + +Fecha §1.4 Fiscal minimo (parcial — #15 NFS-e fica pra depois). + +src/utils/valorExtenso.js — helper pt-BR completo ate 999 milhoes. +"R$ 1.234,56" -> "mil duzentos e trinta e quatro reais e cinquenta +e seis centavos". + +DocumentGenerate.service estendido: +- loadTherapistData puxa professional_registration_type/numero/uf + (#5 migration) e auto-formata terapeuta_registro: "CRP 12345/SP". + terapeuta_crp legacy mantido pra compat. +- loadClinicData formata tenants.cpf_cnpj (11 dig CPF, 14 dig CNPJ). +- loadAllVariables aceita extras + computa valor + valor_extenso + + forma_pagamento. +- saveGeneratedDocument ganha templateTipo + mapping + TEMPLATE_TYPE_TO_DOC_TYPE (recibo_pagamento -> 'recibo', laudo -> + 'laudo' etc). Antes era hardcoded 'laudo' pra TUDO — bug. +- emitirReciboParaSessao(eventoId, opts) — quick path: busca + template, carrega vars, gera PDF, salva, download. One-call. + +Migration 20260521000008 substitui no template recibo_pagamento +"Psicologo(a) - CRP {{terapeuta_crp}}" por "{{terapeuta_registro}}". +Universal pra qualquer conselho (CRP/CRM/CRFa/CREFITO/CRESS/CRN). + +DocumentTemplates.service.TEMPLATE_VARIABLES ganha 4 entries de +registro profissional. useDocumentGenerate passa templateTipo. + +AgendaEventoFinanceiroPanel ganha botao "Emitir recibo" outlined +quando record.status === 'paid'. Toast + loading state. + +PROXIMO: UX §1.3 (busca global + recently viewed + papel timbrado ++ relatorios export) OU sweep residual (M4 cutover billing decisoes +#2/#3/#6). diff --git a/development/02-auditoria/PADRONIZACAO.md b/development/02-auditoria/PADRONIZACAO.md index 5476a5f..76cfc89 100644 --- a/development/02-auditoria/PADRONIZACAO.md +++ b/development/02-auditoria/PADRONIZACAO.md @@ -113,6 +113,8 @@ Do `project_graphify_findings_20260504`: - #7 (assinatura eletrônica no portal): 2 migrations RPC — `20260521000006` cria `sign_document_by_signature_id` + `sign_document_by_token` + `get_signable_document_by_token` (IP/UA capturados server-side via `inet_client_addr()` + `current_setting('request.headers')`); `20260521000007` cria `list_my_signatures` (cruzamento auth.uid() por 3 caminhos). `DocumentSignatures.service` estendido. `useDocumentSignatures` composable novo. `PortalDocumentos.vue` lista pendências do paciente logado. `SharedDocumentPage.vue` estendida com painel azul de assinatura (aviso LGPD + checkbox aceite + Assinar/Recusar). `DocumentSignatureDialog` (terapeuta-side, já existia) ganha checkbox "Gerar link público" + select de validade + bloco com URL gerado/copy. - #8 (nome social): JÁ INTEGRADO — `patients.nome_social` schema existia + UI em 7 arquivos. - #9 (especialidades): `20260521000004_specialties.sql` (tabela + profile_specialties M:N + RLS) + `seed_050_specialties.sql` (33 specialties) + `src/services/specialtiesService.js`. +- [x] **Recibo profissional PDF (#14 · 2026-05-21)** — `valorExtenso.js` helper pt-BR. `DocumentGenerate.service` puxa registro profissional do profile (auto-formato `CRP 12345/SP`), formata `cpf_cnpj` do tenant, computa `valor`+`valor_extenso`, mapeia `templateTipo` → `tipo_documento` (recibo_pagamento → 'recibo'). Migration `20260521000008` substitui `{{terapeuta_crp}}` por `{{terapeuta_registro}}` no template — universal pra qualquer conselho. `emitirReciboParaSessao(eventoId, opts)` é quick path one-call. Botão "Emitir recibo" no `AgendaEventoFinanceiroPanel` quando `record.status === 'paid'`. #15 NFS-e ainda em aberto. +- [ ] NFS-e emissão (#15) — Esforço L, decisão de provider pendente (Focus NF-e vs prefeitura direta). - [ ] E2E Playwright crítico (#16) - [ ] Sentry (#18)