399 lines
7.2 KiB
Markdown
399 lines
7.2 KiB
Markdown
# 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
|