feat(quotes): anexo de conformidade ANATEL/RGC no PDF de oferta
Porta o anexo regulatório do legado (Resolução Anatel 765/2023, RGC, recorte STFC) com fidelidade total ao conteúdo legal, incluindo a seção de tarifação — em vez do html2canvas+jsPDF client-side do legado, usa o Chromium server-side já construído para Documents. Schema: products ganha service_type/metered/tariff_rates/has_ldi (migration 1788525270647) — campos que a migration original de products tinha deliberadamente deferido. Snapshot no item da oferta na criação (nunca referência viva ao produto). Novo pacote compartilhado packages/domain-shared/src/telecom para o catálogo de tipos e legendas de tarifação. Endpoint GET /v1/quotes/:id/anatel-pdf (400 sem item STFC), sempre renderizado ao vivo (nunca cacheado, já que o conteúdo deriva de updated_at). Frontend: campos de produto/oferta necessários + "Baixar PDF ANATEL" na tela de detalhe da oferta. Inclui também o botão de download de PDF em Documentos (endpoint já existia, faltava o link na UI). Verificado ao vivo através do container real: PDF gerado com Chromium de verdade, texto extraído confere byte a byte com os valores computados (multa, datas, tarifas, resumo financeiro). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BcWWuKfykGtUweXmHD6cKx
This commit is contained in:
@@ -484,3 +484,35 @@ Teste de integração novo (`test/documents-pdf.spec.ts`, 3 testes, `@eden/integ
|
||||
|
||||
### Pendências
|
||||
PDF de Oferta/Orçamento compatível com ANATEL (Resolução 765/2023) ainda não construído — próximo item natural desta sequência, usando o mesmo `renderPdf`. Módulo de Assinatura Eletrônica completo (envelopes/signers/OTP/hash-chain) ainda não iniciado — item maior, sensível o suficiente para merecer leva própria dedicada, não apressada. Regras de negócio do legado em torno de edição/trava de Orçamento-como-Contrato (lock ao vincular `client_registration_id`, override só por `super_admin`) ainda não avaliadas contra o modelo de Contrato do EDEN (ADR-0006).
|
||||
|
||||
---
|
||||
|
||||
## Anexo de conformidade ANATEL/RGC no PDF de Oferta (Quotes)
|
||||
|
||||
Data: 2026-09-04. Continuação direta da leva anterior — usuário confirmou que a parte de conteúdo regulatório precisava ser exata, não aproximada de memória. Dois subagentes `fork` extraíram o conteúdo verbatim do legado antes de qualquer código ser escrito: (1) `BackofficeAnatelPDFTemplate.jsx` (texto legal, fórmulas computadas, ordem dos campos), (2) o schema real de `service_type`/`metered`/`tariff_rates`/`has_ldi` em `products` (baseline-schema.js).
|
||||
|
||||
### Decisão de escopo confirmada com o usuário
|
||||
|
||||
O anexo do legado depende de `service_type`/`metered`/`tariff_rates`/`has_ldi` por item — campos que a migration `1788438907074_products.cjs` **deliberadamente** excluiu ("legacy telecom-billing specifics que belong to a later phase"). Perguntei ao usuário como proceder (gerar conteúdo regulatório sobre uma base incompleta era um risco real de compliance) — escolheu **expandir o schema primeiro**, com fidelidade total ao legado incluindo a seção de tarifação STFC.
|
||||
|
||||
### Schema (`packages/database/migrations/1788525270647_products-service-type-tariff.cjs`)
|
||||
|
||||
`products` ganha `service_type` (CHECK nos 4 valores do legado: STFC/Serviço PABX/SVA (locação)/Serviço software), `metered`, `minutes_allowance`, `tariff_rates` (jsonb, formato `{TIPO: {normal, reduced}}`), `has_ldi`. `quotes` ganha `sales_rep_name` (impresso no bloco de assinatura). Novo pacote compartilhado `packages/domain-shared/src/telecom/service-types.ts` (catálogo de tipos, legendas de tarifação verbatim do legado, `formatCPF`/`formatCNPJ` adicionados a `br-documents.ts`) — consumido por `@eden/database`, `apps/api` e `apps/core-web`.
|
||||
|
||||
**Snapshot, não referência viva**: `QuotesService.buildItems()` copia `service_type`/`metered`/`minutesAllowance`/`tariffRates`/`hasLdi` do produto para o item no momento da criação da oferta (mesmo comportamento do legado, confirmado pelo subagente) — editar o produto depois nunca muda retroativamente a disclosure regulatória de uma oferta já emitida.
|
||||
|
||||
### `apps/api/src/quotes/anatel-offer-template.ts` (novo)
|
||||
|
||||
Gera o HTML completo do anexo — todos os campos do legado portados com fidelidade: Prazo de Comercialização (10 dias corridos a partir de `quote.updated_at`, rótulo exato do art. 3º XI, confirmado que NÃO é "Prazo de Oferta"), Prazo de Vigência/Permanência, Multa por Rescisão Antecipada (usa `computeSavings().beneficioTotalFidelidade` — `pricing.ts` já tinha essa fórmula pronta desde a leva de Quotes, nunca usada até agora), Critério/Data-base de Reajuste, tabela de itens agrupada por `service_type`, seção de Tarifação (LC/LDN/VC1/VC2/VC3/LDI, só renderiza para itens `metered`, legenda verbatim), condição especial, resumo financeiro, assinaturas. Placeholder `[A DEFINIR]` para CPF/CNPJ do cliente quando a oferta ainda não tem `client_registration_id` vinculado (nunca inventa um documento).
|
||||
|
||||
**Simplificação deliberada e documentada**: sem o split automático software/não-software do legado (`splitQuoteByServiceType.js`) — esta leva sempre gera um único PDF cobrindo todos os itens da oferta. Renderizado sempre ao vivo (nunca cacheado como os Documents), porque o conteúdo regulatório deriva de `updated_at` — um PDF salvo ficaria defasado assim que a oferta fosse editada de novo.
|
||||
|
||||
Novo endpoint `GET /v1/quotes/:id/anatel-pdf` — 400 se a oferta não tiver nenhum item STFC (o documento inteiro existe para essa disclosure, art. 21 §3º do RGC).
|
||||
|
||||
### Frontend
|
||||
|
||||
`ProductFormPage`: novo card "Regulatório (ANATEL/RGC)" — tipo de serviço, franquia de minutos, tarifado por minuto, LDI, tabela de tarifas (só aparece se "tarifado por minuto" marcado). `QuoteFormPage`: campo "Responsável comercial". `QuoteDetailPage`: botão "Baixar PDF ANATEL" (só aparece se a oferta tiver item STFC, mesma regra do backend) + campo "Responsável comercial" no resumo.
|
||||
|
||||
### Verificação
|
||||
|
||||
Teste de integração novo (`test/anatel-pdf.spec.ts`, 3 testes, `renderPdf` mockado como nos outros specs de PDF — o que está sob teste é o conteúdo regulatório computado, não o Chromium em si): confirma snapshot correto dos campos do produto no item, todos os campos regulatórios computados corretos no HTML (datas, fórmula da multa, tabela de tarifação, texto VoIP, campos fixos), e 400 para oferta sem item STFC. Suíte completa: 39/39 verdes (36→39). `pnpm turbo run typecheck build --force` (28/28).
|
||||
|
||||
Reference in New Issue
Block a user