# Task H.5.2: PDFME Price Table Input Normalization ## Goal แก้ปัญหา PDFME ไม่แสดงข้อความในตารางราคา Current template field: ```json { "name": "quotation_price_data", "type": "table", "content": "[[\"Price (Exclude VAT)\",\"{quotation_price}\",\" \",\"{currency}\"]]" } ``` Expected output: ```txt Price (Exclude VAT) ฿500,000.00 THB ``` Root cause: PDFME table field นี้ควรได้รับ input ตาม schema name: ```txt quotation_price_data ``` ในรูปแบบ: ```ts [ ["Price (Exclude VAT)", "฿500,000.00", " ", "THB"] ] ``` ไม่ควร rely กับการ map cell ย่อย `{quotation_price}` และ `{currency}` ภายใน table content --- # Must Read ```txt docs/implementation/task-h5-pdf-mapping-audit-visual-parity.md docs/business/pdf-mapping-registry.md docs/business/pdf-placeholder-registry.md docs/implementation/task-h51-pdf-integrity-audit.md src/features/crm/quotations/document/server/pdfme-transforms.ts src/features/crm/quotations/document/server/service.ts src/features/foundation/document-template/server/service.ts src/features/foundation/pdf-generator/server/service.ts src/db/seeds/foundation.seed.ts scripts/audit-pdf-runtime-payload.ts scripts/audit-payload-parity.ts scripts/generate-pdf-integrity-report.ts ``` --- # Scope H5.2.1: Add PDFME Price Table Field Update quotation document builder: ```txt src/features/crm/quotations/document/server/service.ts ``` Add to `documentData.pdfme`: ```ts quotation_price_data: string[][]; ``` Expected shape: ```ts [ [ "Price (Exclude VAT)", formatPdfCurrency(quotation.subtotal, quotation.currency), " ", quotation.currency || "THB" ] ] ``` Rules: * first column must be `"Price (Exclude VAT)"` * second column must be formatted currency string such as `฿500,000.00` * third column is `" "` to match template spacing * fourth column must be currency code such as `THB` * never return `undefined` * if price is missing, use `"-"` * if currency is missing, fallback to `"THB"` --- # Scope H5.2.2: Keep Scalar Fields For Compatibility Keep existing fields: ```ts pdfme.quotation_price pdfme.currency ``` But table rendering must use: ```txt pdfme.quotation_price_data ``` Do not remove existing fields because other templates or audits may still reference them. --- # Scope H5.2.3: Template Mapping Seed Update Update: ```txt src/db/seeds/foundation.seed.ts ``` Ensure mapping exists: ```txt quotation_price_data -> pdfme.quotation_price_data ``` With: ```txt dataType = table defaultValue = [["Price (Exclude VAT)", "-", " ", "THB"]] sortOrder appropriate ``` Retain mappings if used elsewhere: ```txt quotation_price -> pdfme.quotation_price currency -> pdfme.currency ``` But do not depend on them for `quotation_price_data`. Rules: * idempotent seed * update existing incorrect mapping * no duplicate mapping * no hardcoded organizationId * apply to active ALLA / ONVALLA template versions --- # Scope H5.2.4: Template Mapping Resolver Update: ```txt src/features/foundation/document-template/server/service.ts ``` Ensure `mapDocumentDataToTemplateInput()` preserves table input when source value is already: ```ts string[][] ``` For mapping: ```txt placeholderKey = quotation_price_data dataType = table sourcePath = pdfme.quotation_price_data ``` Expected template input: ```ts { quotation_price_data: [ ["Price (Exclude VAT)", "฿500,000.00", " ", "THB"] ] } ``` Do not stringify this table. Do not flatten it. Do not attempt nested placeholder interpolation for this field. --- # Scope H5.2.5: Template Placeholder Audit Update Update: ```txt scripts/audit-pdf-template-inventory.ts scripts/audit-pdf-mapping-coverage.ts scripts/audit-pdf-runtime-payload.ts scripts/audit-payload-parity.ts scripts/generate-pdf-integrity-report.ts ``` Audit must recognize: ```txt quotation_price_data ``` as the table field to verify. Expected checks: ```txt quotation_price_data exists in template schema quotation_price_data mapping exists quotation_price_data sourcePath = pdfme.quotation_price_data quotation_price_data resolved type = string[][] quotation_price_data row count >= 1 quotation_price_data[0][1] contains formatted currency quotation_price_data[0][3] contains currency code ``` --- # Scope H5.2.6: Approved Snapshot Parity Fix Approved snapshot must store: ```ts templateInput.quotation_price_data ``` And it must match current runtime payload unless quotation data changed after approval. For fixture `QT-H5-AUDIT`, after regenerating approved PDF: Expected: ```txt Approved Snapshot Parity = PASS inconsistentKeys = [] ``` Rules: * if approved snapshot exists with old data, regenerate artifact only in fixture/dev environment * do not silently overwrite locked production artifacts * production regeneration must require explicit void/regenerate flow later --- # Scope H5.2.7: PDFME Input Compatibility Because current template content still has nested tokens: ```txt {quotation_price} {currency} ``` inside: ```txt quotation_price_data ``` Runtime should still prioritize input key: ```txt quotation_price_data ``` over nested tokens. Optional safe improvement: If needed, update the active template schema content from: ```json "[[\"Price (Exclude VAT)\",\"{quotation_price}\",\" \",\"{currency}\"]]" ``` to: ```json "[[\"Price (Exclude VAT)\",\"-\",\" \",\"THB\"]]" ``` But only if PDFME requires removing nested placeholders for table input to render correctly. Do not make layout changes. --- # Scope H5.2.8: Verification Run: ```txt npm run audit:pdf ``` Expected: ```txt Template Version Integrity: PASS Placeholder Integrity: PASS Payload Parity: PASS Topic Runtime: PASS Approved Snapshot Parity: PASS Overall Status: PASS ``` Also verify actual preview / PDF visually shows: ```txt Price (Exclude VAT) ฿500,000.00 THB ``` --- # Scope H5.2.9: Documentation Update: ```txt docs/business/pdf-mapping-registry.md docs/business/pdf-placeholder-registry.md docs/implementation/task-h51-pdf-integrity-audit.md docs/implementation/technical-debt.md ``` Document: ```txt quotation_price_data is the canonical PDFME table field for price display. quotation_price and currency remain scalar compatibility fields. Do not use nested table placeholders for canonical price table rendering. ``` --- # Explicit Non-Scope Do NOT implement: ```txt signature image draw signature new PDF template design visual designer approved artifact void/regenerate UI report center currency exchange calculation multi-currency tax logic ``` --- # Output After completion, summarize: 1. Files Modified 2. PDFME Price Table Field Added 3. Mapping Seed Updated 4. Resolver Behavior Confirmed 5. Audit Updated 6. Approved Snapshot Parity Result 7. Remaining Risks --- # Definition of Done Task H.5.2 passes when: * `pdfme.quotation_price_data` exists * `quotation_price_data` maps to `pdfme.quotation_price_data` * `quotation_price_data` is `string[][]` * PDF renders `Price (Exclude VAT) ฿500,000.00 THB` * scalar `quotation_price` and `currency` remain available * approved snapshot stores `templateInput.quotation_price_data` * `npm run audit:pdf` returns Overall Status PASS * `inconsistentKeys` is empty