531 lines
6.1 KiB
Markdown
531 lines
6.1 KiB
Markdown
# Task H.3: Approval Signature Strategy
|
|
|
|
## Goal
|
|
|
|
ทำให้ PDF ใบเสนอราคาสามารถแสดงข้อมูลผู้จัดทำ ผู้อนุมัติ และผู้มีอำนาจอนุมัติได้อย่างถูกต้อง
|
|
|
|
รองรับทั้ง:
|
|
|
|
```txt
|
|
Preview PDF
|
|
Approved PDF
|
|
Approved Snapshot
|
|
Document Artifact
|
|
```
|
|
|
|
โดยข้อมูลลายเซ็นต้องมาจาก Approval Workflow จริง ไม่ใช่ค่าคงที่ใน Template
|
|
|
|
---
|
|
|
|
# Background
|
|
|
|
Task H.2 เพิ่ม:
|
|
|
|
```txt
|
|
Dynamic Topic Engine
|
|
PDFME Runtime Mapping
|
|
Template Mapping Resolver
|
|
```
|
|
|
|
Task H.1 เพิ่ม:
|
|
|
|
```txt
|
|
Approved Snapshot
|
|
Artifact Storage
|
|
```
|
|
|
|
Task H.3 จะเติมส่วนที่ยังขาด:
|
|
|
|
```txt
|
|
Prepared By
|
|
Approved By
|
|
Authorized By
|
|
Position
|
|
Approval Timeline Resolution
|
|
```
|
|
|
|
---
|
|
|
|
# Current Problem
|
|
|
|
Template ปัจจุบันมี placeholder เช่น:
|
|
|
|
```txt
|
|
app1
|
|
app1_position
|
|
|
|
app2
|
|
app2_position
|
|
|
|
app3
|
|
app3_position
|
|
```
|
|
|
|
แต่ยังไม่มี strategy กลางสำหรับดึงข้อมูลจริงจาก:
|
|
|
|
```txt
|
|
quotation
|
|
approval workflow
|
|
approval actions
|
|
membership
|
|
business role
|
|
```
|
|
|
|
---
|
|
|
|
# Scope H3.1 Signature Data Contract
|
|
|
|
Create:
|
|
|
|
```txt
|
|
src/features/crm/quotations/document/signature.types.ts
|
|
```
|
|
|
|
Define:
|
|
|
|
```ts
|
|
type SignatureBlock = {
|
|
preparedBy: {
|
|
name: string;
|
|
position: string;
|
|
};
|
|
|
|
approvedBy: {
|
|
name: string;
|
|
position: string;
|
|
};
|
|
|
|
authorizedBy: {
|
|
name: string;
|
|
position: string;
|
|
};
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
# Scope H3.2 Position Resolution Strategy
|
|
|
|
Create:
|
|
|
|
```txt
|
|
src/features/crm/quotations/document/signature-position.ts
|
|
```
|
|
|
|
Resolve position from:
|
|
|
|
```txt
|
|
membership.businessRole
|
|
```
|
|
|
|
Recommended mapping:
|
|
|
|
```txt
|
|
sales
|
|
→ Sales Engineer
|
|
|
|
sales_support
|
|
→ Sales Support
|
|
|
|
sales_manager
|
|
→ Sales Manager
|
|
|
|
department_manager
|
|
→ Department Manager
|
|
|
|
top_manager
|
|
→ General Manager
|
|
```
|
|
|
|
Rules:
|
|
|
|
Do NOT hardcode display strings inside PDF generator.
|
|
|
|
Source from:
|
|
|
|
```txt
|
|
crm_job_title
|
|
```
|
|
|
|
master option when available.
|
|
|
|
Fallback:
|
|
|
|
```txt
|
|
businessRole label
|
|
```
|
|
|
|
---
|
|
|
|
# Scope H3.3 Prepared By Resolution
|
|
|
|
Prepared By source:
|
|
|
|
Priority:
|
|
|
|
```txt
|
|
quotation.salesmanId
|
|
```
|
|
|
|
Fallback:
|
|
|
|
```txt
|
|
quotation.createdBy
|
|
```
|
|
|
|
Output:
|
|
|
|
```txt
|
|
preparedBy.name
|
|
preparedBy.position
|
|
```
|
|
|
|
Rules:
|
|
|
|
Must resolve display name.
|
|
|
|
Never use raw user id.
|
|
|
|
---
|
|
|
|
# Scope H3.4 Approved By Resolution
|
|
|
|
Resolve from approval workflow history.
|
|
|
|
Source:
|
|
|
|
```txt
|
|
crm_approval_actions
|
|
```
|
|
|
|
Rules:
|
|
|
|
Find latest approved action from:
|
|
|
|
```txt
|
|
sales_manager
|
|
```
|
|
|
|
or
|
|
|
|
```txt
|
|
department_manager
|
|
```
|
|
|
|
depending on workflow configuration.
|
|
|
|
Output:
|
|
|
|
```txt
|
|
approvedBy.name
|
|
approvedBy.position
|
|
```
|
|
|
|
---
|
|
|
|
# Scope H3.5 Authorized By Resolution
|
|
|
|
Resolve from final approval step.
|
|
|
|
Source:
|
|
|
|
```txt
|
|
crm_approval_actions
|
|
```
|
|
|
|
Rules:
|
|
|
|
Find final approved action.
|
|
|
|
Expected role:
|
|
|
|
```txt
|
|
top_manager
|
|
```
|
|
|
|
Output:
|
|
|
|
```txt
|
|
authorizedBy.name
|
|
authorizedBy.position
|
|
```
|
|
|
|
---
|
|
|
|
# Scope H3.6 Signature Resolver
|
|
|
|
Create:
|
|
|
|
```txt
|
|
src/features/crm/quotations/document/server/signature-resolver.ts
|
|
```
|
|
|
|
Expose:
|
|
|
|
```ts
|
|
resolveQuotationSignatures(
|
|
quotationId,
|
|
organizationId
|
|
)
|
|
```
|
|
|
|
Returns:
|
|
|
|
```ts
|
|
SignatureBlock
|
|
```
|
|
|
|
Responsibilities:
|
|
|
|
```txt
|
|
load quotation
|
|
load approval history
|
|
resolve users
|
|
resolve positions
|
|
build final signature object
|
|
```
|
|
|
|
---
|
|
|
|
# Scope H3.7 PDF Mapping Integration
|
|
|
|
Update:
|
|
|
|
```txt
|
|
src/features/crm/quotations/document/server/service.ts
|
|
```
|
|
|
|
Inject:
|
|
|
|
```txt
|
|
signatures.preparedBy.name
|
|
signatures.preparedBy.position
|
|
|
|
signatures.approvedBy.name
|
|
signatures.approvedBy.position
|
|
|
|
signatures.authorizedBy.name
|
|
signatures.authorizedBy.position
|
|
```
|
|
|
|
Into:
|
|
|
|
```txt
|
|
documentData
|
|
templateInput
|
|
approvedSnapshot
|
|
```
|
|
|
|
---
|
|
|
|
# Scope H3.8 PDFME Placeholder Mapping
|
|
|
|
Update seed mappings.
|
|
|
|
Expected:
|
|
|
|
```txt
|
|
app1
|
|
→ signatures.preparedBy.name
|
|
|
|
app1_position
|
|
→ signatures.preparedBy.position
|
|
|
|
app2
|
|
→ signatures.approvedBy.name
|
|
|
|
app2_position
|
|
→ signatures.approvedBy.position
|
|
|
|
app3
|
|
→ signatures.authorizedBy.name
|
|
|
|
app3_position
|
|
→ signatures.authorizedBy.position
|
|
```
|
|
|
|
Rules:
|
|
|
|
Idempotent seed.
|
|
|
|
Update existing mappings if incorrect.
|
|
|
|
---
|
|
|
|
# Scope H3.9 Approved Snapshot Integration
|
|
|
|
Update:
|
|
|
|
```txt
|
|
prepareApprovedQuotationSnapshot()
|
|
```
|
|
|
|
Snapshot must store:
|
|
|
|
```txt
|
|
resolved signatures
|
|
```
|
|
|
|
Purpose:
|
|
|
|
Future PDF regeneration must preserve:
|
|
|
|
```txt
|
|
who approved
|
|
who authorized
|
|
```
|
|
|
|
even if users later change.
|
|
|
|
---
|
|
|
|
# Scope H3.10 Preview Behavior
|
|
|
|
Preview PDF:
|
|
|
|
```txt
|
|
resolve live signatures
|
|
```
|
|
|
|
Approved PDF:
|
|
|
|
```txt
|
|
prefer approved snapshot signatures
|
|
```
|
|
|
|
Rules:
|
|
|
|
Approved artifact must remain immutable.
|
|
|
|
---
|
|
|
|
# Scope H3.11 UI Visibility
|
|
|
|
Update quotation detail.
|
|
|
|
Add section:
|
|
|
|
```txt
|
|
Approval Signatures
|
|
```
|
|
|
|
Display:
|
|
|
|
```txt
|
|
Prepared By
|
|
Approved By
|
|
Authorized By
|
|
```
|
|
|
|
with:
|
|
|
|
```txt
|
|
name
|
|
position
|
|
approval timestamp
|
|
```
|
|
|
|
if available.
|
|
|
|
---
|
|
|
|
# Scope H3.12 Verification
|
|
|
|
Create:
|
|
|
|
```txt
|
|
scripts/verify-task-h3.js
|
|
```
|
|
|
|
Verify:
|
|
|
|
```txt
|
|
preparedBy exists
|
|
approvedBy exists
|
|
authorizedBy exists
|
|
|
|
app1 mapped
|
|
app2 mapped
|
|
app3 mapped
|
|
|
|
snapshot contains signatures
|
|
|
|
approved PDF contains names
|
|
```
|
|
|
|
---
|
|
|
|
# ADR
|
|
|
|
Create:
|
|
|
|
```txt
|
|
docs/adr/0012-approval-signature-strategy.md
|
|
```
|
|
|
|
Freeze:
|
|
|
|
```txt
|
|
Prepared By rule
|
|
Approved By rule
|
|
Authorized By rule
|
|
Position resolution rule
|
|
Snapshot immutability rule
|
|
```
|
|
|
|
---
|
|
|
|
# Explicit Non-Scope
|
|
|
|
Do NOT implement:
|
|
|
|
```txt
|
|
Digital signature
|
|
Image signature
|
|
Certificate signature
|
|
PKI
|
|
e-Signature
|
|
QR verification
|
|
Stamp image upload
|
|
```
|
|
|
|
Only text-based approval identity.
|
|
|
|
---
|
|
|
|
# Output
|
|
|
|
1. Files Added
|
|
2. Files Modified
|
|
3. Signature Resolution Strategy
|
|
4. Position Resolution Strategy
|
|
5. PDF Mapping Changes
|
|
6. Snapshot Changes
|
|
7. Verification Result
|
|
8. ADR Added
|
|
9. Remaining Risks
|
|
|
|
---
|
|
|
|
# Definition of Done
|
|
|
|
✔ Prepared By resolves correctly
|
|
|
|
✔ Approved By resolves correctly
|
|
|
|
✔ Authorized By resolves correctly
|
|
|
|
✔ Position resolves correctly
|
|
|
|
✔ PDF Preview displays signatures
|
|
|
|
✔ Approved PDF displays signatures
|
|
|
|
✔ Approved Snapshot stores signatures
|
|
|
|
✔ app1/app2/app3 mappings work
|
|
|
|
✔ Artifact remains immutable
|
|
|
|
✔ ADR created
|