Files
alla-allaos-fullstack/plans/task-h.5.2.md
phaichayon 51d67ef7c2 task-h.5.3
2026-06-19 17:15:28 +07:00

7.2 KiB

Task H.5.2: PDFME Price Table Input Normalization

Goal

แก้ปัญหา PDFME ไม่แสดงข้อความในตารางราคา

Current template field:

{
  "name": "quotation_price_data",
  "type": "table",
  "content": "[[\"Price (Exclude VAT)\",\"{quotation_price}\",\" \",\"{currency}\"]]"
}

Expected output:

Price (Exclude VAT)    ฿500,000.00        THB

Root cause:

PDFME table field นี้ควรได้รับ input ตาม schema name:

quotation_price_data

ในรูปแบบ:

[
  ["Price (Exclude VAT)", "฿500,000.00", " ", "THB"]
]

ไม่ควร rely กับการ map cell ย่อย {quotation_price} และ {currency} ภายใน table content


Must Read

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:

src/features/crm/quotations/document/server/service.ts

Add to documentData.pdfme:

quotation_price_data: string[][];

Expected shape:

[
  [
    "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:

pdfme.quotation_price
pdfme.currency

But table rendering must use:

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:

src/db/seeds/foundation.seed.ts

Ensure mapping exists:

quotation_price_data -> pdfme.quotation_price_data

With:

dataType = table
defaultValue = [["Price (Exclude VAT)", "-", " ", "THB"]]
sortOrder appropriate

Retain mappings if used elsewhere:

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:

src/features/foundation/document-template/server/service.ts

Ensure mapDocumentDataToTemplateInput() preserves table input when source value is already:

string[][]

For mapping:

placeholderKey = quotation_price_data
dataType = table
sourcePath = pdfme.quotation_price_data

Expected template input:

{
  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:

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:

quotation_price_data

as the table field to verify.

Expected checks:

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:

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:

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:

{quotation_price}
{currency}

inside:

quotation_price_data

Runtime should still prioritize input key:

quotation_price_data

over nested tokens.

Optional safe improvement:

If needed, update the active template schema content from:

"[[\"Price (Exclude VAT)\",\"{quotation_price}\",\" \",\"{currency}\"]]"

to:

"[[\"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:

npm run audit:pdf

Expected:

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:

Price (Exclude VAT)    ฿500,000.00        THB

Scope H5.2.9: Documentation

Update:

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:

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:

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