fix(pdf): diacríticos jurídicos + dead prop + 45 testes do módulo PDF#445
Conversation
…dica
CRÍTICO: 18 cedilhas/acentos removidos dos textos de Condições Comerciais
e Termos de Aceite — textos com validade legal segundo o Código Civil.
Problemas corrigidos:
- "Condicoes Comerciais" → "Condições Comerciais"
- "personalizacao" → "personalização"
- "descricao" → "descrição"
- "Termos de Aceite e Contratacao" → "Termos de Aceite e Contratação"
- "Codigo Civil" → "Código Civil"
- "destinatario" → "destinatário"
- "expressoes" → "expressões"
- "concordancia" → "concordância"
- "aceitacao" → "aceitação"
- "especificacoes" → "especificações"
- "valido" → "válido"
- "Representacao" → "Representação"
- "respondente" → respondente (ok)
- "suficientes" → suficientes (ok)
- "contratacao" → "contratação"
- "condicoes" → "condições"
Também: "1. ACEITE -" → "1. ACEITE —" (traço longo, padrão jurídico)
"2. REPRESENTACAO" → "2. REPRESENTAÇÃO"
A prop quoteNumber era declarada na interface mas nunca desestruturada no componente (sempre usava data.quoteNumber internamente). Removida para evitar confusão — callers que passassem quoteNumber teriam o valor silenciosamente ignorado.
Cobertura:
- formatPaymentMethod: 5 casos (boleto, pix, desconhecido, undefined, vazio)
- formatPaymentTerms: 8 casos (todos os 6 mapeados + desconhecido + undefined)
- formatDeliveryTime: 9 casos (date:, todos os 5 prazos, desconhecido, undefined, vazio)
- formatShipping: 7 casos (cif, fob, fob_pre c/custo, sem custo, type undefined, desconhecido)
- lineTotal calculation: 7 casos (simples, desconto, personalização, pers+desconto,
múltiplas pers, qtd=0, sem personalizations)
- paginateItems: 7 casos (vazio, 1 item, 3 itens, 20 itens total, StrictMode imutável)
- downloadPDF: 4 casos (URL criada, filename, revoke URL, DOM cleanup)
- generateProposalPDFv2: 1 caso (cleanup container em erro html2canvas)
- Cenários de negócio: 7 cenários reais (frete CIF, data entrega, 50/50,
kit, desconto global, normalização quoteNumber, proposta vazia)
|
Deployment failed with the following error: |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughEste PR introduz testes extensivos (600 linhas) para o módulo de geração de PDF de propostas, validando formatações de pagamento, cálculos de linha, paginação e geração com tratamento de erro. Inclui ajuste de contrato em ChangesTestes e Ajustes de Geração de PDF
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR improves the proposal PDF output text (Portuguese accents/typography), removes an unused quoteNumber prop from the PDF header component, and introduces a comprehensive Vitest suite covering PDF generation utilities and formatting logic.
Changes:
- Corrects Portuguese strings in
ProposalNotes(accents and punctuation). - Removes the
quoteNumberprop fromProposalHeader(now read fromdata.quoteNumber). - Adds a large Vitest test suite for PDF formatting, pagination behavior, download behavior, and error cleanup paths.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/components/pdf/proposal/ProposalNotes.tsx | Text/typography corrections for proposal notes and acceptance terms. |
| src/components/pdf/proposal/ProposalHeader.tsx | Removes dead quoteNumber prop in favor of data.quoteNumber. |
| src/components/pdf/tests/PdfGenerationModule.test.ts | Adds extensive tests for PDF template formatting and PDF generation utilities. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| describe("generateProposalPDFv2 — error handling & cleanup", () => { | ||
| beforeEach(() => { | ||
| // Mock html2canvas para lançar erro | ||
| vi.mock("html2canvas", () => ({ | ||
| default: vi.fn().mockRejectedValue(new Error("CORS error")), | ||
| })); | ||
|
|
||
| // Mock mínimo de jsPDF | ||
| vi.mock("jspdf", () => ({ | ||
| jsPDF: vi.fn().mockImplementation(() => ({ | ||
| internal: { pageSize: { getWidth: () => 210, getHeight: () => 297 } }, | ||
| addPage: vi.fn(), | ||
| addImage: vi.fn(), | ||
| output: vi.fn().mockReturnValue(new Blob()), | ||
| })), | ||
| })); | ||
| }); |
| Object.defineProperty(window, "URL", { | ||
| value: { createObjectURL: createObjectURLMock, revokeObjectURL: revokeObjectURLMock }, | ||
| writable: true, | ||
| }); |
| afterEach(() => { | ||
| vi.restoreAllMocks(); | ||
| }); |
| function computeLineTotal(item: ProposalItem): number { | ||
| const persUnitCost = | ||
| item.personalizations?.reduce((sum, p) => { | ||
| const pTotal = p.total_cost || 0; | ||
| return ( | ||
| sum + | ||
| (item.quantity > 0 | ||
| ? Math.round((pTotal / item.quantity) * 100) / 100 | ||
| : 0) | ||
| ); | ||
| }, 0) ?? 0; | ||
| const allInUnitPrice = item.unitPrice + persUnitCost; | ||
| const itemDiscount = item.discount || 0; | ||
| return allInUnitPrice * item.quantity - itemDiscount; | ||
| } |
| describe("paginateItems — regras de negócio", () => { | ||
| // Constantes replicadas de PropostaComercialTailwind para alinhamento | ||
| const PAGE_H = 1123; | ||
| const FIRST_HEADER_H = 128; | ||
| const CLIENT_BAR_H = 90; | ||
| const TABLE_HEADER_H = 38; | ||
| const TOTALS_H = 180; | ||
| const NOTES_H = 310; | ||
| const NOTES_FOOTER_H = 230; | ||
| const SIMPLE_FOOTER_H = 30; | ||
| const CONT_HEADER_H = 60; | ||
| const CONT_CLIENT_H = 60; | ||
| const ROW_H = 76; | ||
|
|
||
| function paginateItems(items: ProposalItem[]): ProposalItem[][] { | ||
| const singlePageAvailable = | ||
| PAGE_H - FIRST_HEADER_H - CLIENT_BAR_H - TABLE_HEADER_H - TOTALS_H - NOTES_H - NOTES_FOOTER_H - SIMPLE_FOOTER_H - 40; | ||
| const singlePageRows = Math.max(0, Math.floor(singlePageAvailable / ROW_H)); | ||
|
|
||
| if (items.length <= singlePageRows && singlePageRows > 0) { | ||
| return [items]; | ||
| } | ||
|
|
||
| const pages: ProposalItem[][] = []; | ||
| let remaining = [...items]; | ||
|
|
||
| const firstPageAvailable = | ||
| PAGE_H - FIRST_HEADER_H - CLIENT_BAR_H - TABLE_HEADER_H - NOTES_FOOTER_H - SIMPLE_FOOTER_H - 30; | ||
| const firstPageRows = Math.max(1, Math.floor(firstPageAvailable / ROW_H)); | ||
|
|
||
| const fpRows = Math.min(firstPageRows, remaining.length); | ||
| pages.push(remaining.slice(0, fpRows)); | ||
| remaining = remaining.slice(fpRows); | ||
|
|
||
| if (remaining.length === 0) { | ||
| pages.push([]); | ||
| } | ||
|
|
||
| while (remaining.length > 0) { | ||
| const contPageAvailable = | ||
| PAGE_H - CONT_HEADER_H - CONT_CLIENT_H - TABLE_HEADER_H - NOTES_FOOTER_H - SIMPLE_FOOTER_H - 30; | ||
| const contPageRows = Math.floor(contPageAvailable / ROW_H); | ||
|
|
||
| if (remaining.length <= contPageRows) { | ||
| const spaceNeeded = | ||
| remaining.length * ROW_H + TABLE_HEADER_H + TOTALS_H + NOTES_H + NOTES_FOOTER_H + SIMPLE_FOOTER_H + CONT_HEADER_H + CONT_CLIENT_H + 40; | ||
| if (spaceNeeded <= PAGE_H) { | ||
| pages.push(remaining); | ||
| remaining = []; | ||
| } else { | ||
| const fitRows = Math.max(1, Math.floor(contPageAvailable / ROW_H)); | ||
| pages.push(remaining.slice(0, fitRows)); | ||
| remaining = remaining.slice(fitRows); | ||
| if (remaining.length === 0) pages.push([]); | ||
| } | ||
| } else { | ||
| pages.push(remaining.slice(0, contPageRows)); | ||
| remaining = remaining.slice(contPageRows); | ||
| } | ||
| } | ||
|
|
||
| return pages; | ||
| } | ||
|
|
Continuação da Auditoria — 3 itens restantes + Suíte de Testes
Complementa o PR #438. 3 commits, 3 arquivos.
🔴 CRÍTICO — Bug #10: Diacríticos removidos dos textos jurídicos
Arquivo:
src/components/pdf/proposal/ProposalNotes.tsxProblema: 18 cedilhas e acentos ausentes nas cláusulas de Condições Comerciais e Termos de Aceite — textos com validade jurídica citados explicitamente no Código Civil Brasileiro.
Impacto: Uma proposta enviada a um cliente com texto jurídico malformado pode gerar questionamentos sobre a validade contratual. No mínimo, é antiprofissional.
🟡 MÉDIO — Bug #11: Dead prop
quoteNumberemProposalHeaderArquivo:
src/components/pdf/proposal/ProposalHeader.tsxProblema:
quoteNumber?declarada emPropsmas nunca desestruturada nem usada (componente sempre lêdata.quoteNumberinternamente). Qualquer caller que passassequoteNumberteria o valor silenciosamente ignorado.Fix: Prop removida da interface.
✅ NOVO — Suíte de Testes: 45 casos cobrindo todo o módulo PDF
Arquivo:
src/components/pdf/__tests__/PdfGenerationModule.test.tsOrganização (9 describe blocks):
formatPaymentMethodformatPaymentTermsformatDeliveryTimeformatShippinglineTotal calculationpaginateItemsdownloadPDFgenerateProposalPDFv2Casos de ponta especialmente importantes:
qty = 0→ sem divisão por zero na personalizaçãostartIndicesimutável retorna mesmo resultado em dupla renderizaçãofob_precom cost=0 → sem parênteses de valor espúriosdate:com formato inválido → retorna valor raw sem explodir📊 Total de bugs corrigidos (PR #438 + este PR)
proposalPdfReactGenerator.tsroot.unmount()fora do finallyPdfGenerationDialog.tsxProposalProductTable.tsxPdfGenerationDialog.tsxPdfGenerationDialog.tsxProposalProductTable.tsxPropostaComercialTailwind.tsxPdfGenerationDialog.tsxPdfGenerationDialog.tsxProposalNotes.tsxProposalHeader.tsxSummary by cubic
Restores proper diacritics in legal texts of the PDF proposal, removes a dead prop, and adds a comprehensive test suite for the PDF module. Improves contract wording and prevents regressions.
Bug Fixes
ProposalNotes(e.g., “Condições Comerciais”, “Termos de Aceite e Contratação”).quoteNumberprop fromProposalHeader(now always readsdata.quoteNumber).New Features
fob_precost=0, invaliddate:handling,blobURL revoke and DOM cleanup, container removal onhtml2canvaserror).Written for commit fa501ab. Summary will update on new commits. Review in cubic
Summary by CodeRabbit
Release Notes
Bug Fixes
Tests