Warranty & Claims — กระบวนการทำงาน (Process flows)
สถาปัตยกรรมและวงจรชีวิตถูกสร้างอัตโนมัติจากโค้ด (dispatch, สถานะ enum ใน CHECK, การเขียน SET status) ส่วน sequence และหมายเหตุเขียนขึ้นเอง
สถาปัตยกรรม
%%{init: {"theme":"base","themeVariables":{"darkMode":true,"background":"#1e1e1e","primaryColor":"#2d2d30","primaryBorderColor":"#569cd6","primaryTextColor":"#d4d4d4","lineColor":"#6796c6","secondaryColor":"#3a3d41","secondaryBorderColor":"#dcdcaa","tertiaryColor":"#252526","tertiaryBorderColor":"#569cd6","clusterBkg":"#252526","clusterBorder":"#569cd6","titleColor":"#569cd6","noteBkgColor":"#3a3d41","noteTextColor":"#dcdcaa"},"flowchart":{"useMaxWidth":false},"state":{"useMaxWidth":false}}}%%
flowchart LR
C["Client"] --> A["Pages Fn claims<br/>bolt_session auth · company_id scope"]
A --> D["dispatch<br/>register_warranty · transfer_warranty · warranty_transfer · claim_intake · rma_quarantine · restock_refurb · claim_disposition · rma_disposition …"]
D --> K["Kernel<br/>erp_document + journal<br/>atomic GL / stock"]
K --> DB[("D1 tables")]
D --> DB
D --> EV["events<br/>append audit trail"]
EV --> DB
DB -.-> T["claims_warranty_registration<br/>claims_warranty_transfer<br/>claims_warranty_case<br/>claims_warranty_claim_line<br/>claims_warranty_entitlement_check<br/>claims_warranty_rma_stock_movement<br/>claims_warranty_triage_decision<br/>claims_warranty_repair_order"]
วงจรชีวิต (Lifecycle)
วงจรชีวิตของเอกสาร Kernel (erp_document.docstatus)
เอกสารทุกฉบับในโมดูลนี้ที่ขยับเงินหรือสต็อกจะถูกโพสต์ผ่าน kernel ที่ใช้ร่วมกัน โดยเดินตาม docstatus ที่กำหนดไว้ตายตัว:
%%{init: {"theme":"base","themeVariables":{"darkMode":true,"background":"#1e1e1e","primaryColor":"#2d2d30","primaryBorderColor":"#569cd6","primaryTextColor":"#d4d4d4","lineColor":"#6796c6","secondaryColor":"#3a3d41","secondaryBorderColor":"#dcdcaa","tertiaryColor":"#252526","tertiaryBorderColor":"#569cd6","clusterBkg":"#252526","clusterBorder":"#569cd6","titleColor":"#569cd6","noteBkgColor":"#3a3d41","noteTextColor":"#dcdcaa"},"flowchart":{"useMaxWidth":false},"state":{"useMaxWidth":false}}}%%
stateDiagram-v2
[*] --> Draft: createDocument (docstatus 0)
Draft --> Submitted: submitDocument (docstatus 1, journal posted)
Submitted --> Cancelled: cancelDocument (docstatus 2, reversed)
Submitted --> [*]
Cancelled --> [*]
claims_warranty_case.status
สถานะ: draft (เริ่มต้น) · accepted · rejected · triaged · in_repair · resolved · closed
| สถานะ | ตั้งค่าโดย (grep จาก SET status='…') |
|---|---|
triaged |
triageClaim |
in_repair |
startRepair, resolveClaim |
claims_warranty_case.operational_status
สถานะ: draft (เริ่มต้น) · triaged · in_repair · resolved · closed · rejected
claims_warranty_claim_line.entitlement_status
สถานะ: in_warranty (เริ่มต้น) · out_of_warranty · unregistered · void · goodwill
claims_warranty_claim_line.line_status
สถานะ: accepted (เริ่มต้น) · rejected · goods_in · triaged · in_repair · in_replacement · in_refund · resolved · closed
| สถานะ | ตั้งค่าโดย (grep จาก SET line_status='…') |
|---|---|
triaged |
triageClaim |
in_repair |
startRepair |
claims_warranty_registration.status
สถานะ: provisional (เริ่มต้น) · active · voided · superseded
Flow สำคัญ: การเปลี่ยนสินค้าตามการรับประกัน (resolve_claim, kind=replace)
เส้นทางที่แตะเงินมากที่สุด: รายการที่ยังอยู่ในประกัน (in-warranty) ถูกปิดด้วยการจ่ายสินค้าชิ้นใหม่ให้แทน เมื่อสินค้าคงคลังถูกตัดออกอย่างถาวร kernel จึงโพสต์ทั้งการตัดสต็อก (stock-out) และ รายการ GL ที่หักล้างกันแบบ atomic โดยมีคีย์กำกับเพื่อให้ replay ได้แบบ idempotent
%%{init: {"theme":"base","themeVariables":{"darkMode":true,"background":"#1e1e1e","primaryColor":"#2d2d30","primaryBorderColor":"#569cd6","primaryTextColor":"#d4d4d4","lineColor":"#6796c6","secondaryColor":"#3a3d41","secondaryBorderColor":"#dcdcaa","secondaryTextColor":"#d4d4d4","tertiaryColor":"#252526","tertiaryBorderColor":"#569cd6","noteBkgColor":"#3a3d41","noteTextColor":"#dcdcaa","clusterBkg":"#252526","clusterBorder":"#569cd6","titleColor":"#569cd6","actorBkg":"#2d2d30","actorBorder":"#569cd6","actorTextColor":"#d4d4d4","signalColor":"#9cdcfe","signalTextColor":"#d4d4d4","noteBkgColor":"#3a3d41","labelBoxBkgColor":"#3a3d41","labelBoxBorderColor":"#dcdcaa"},"flowchart":{"useMaxWidth":false},"sequence":{"useMaxWidth":false},"state":{"useMaxWidth":false},"er":{"useMaxWidth":false}}}%%
sequenceDiagram
participant C as Client
participant FN as claims Fn
participant DB as D1 claims tables
participant K as kernel
participant L as stock ledger + GL
C->>FN: POST action=resolve_claim, kind=replace
FN->>FN: getIdentityAsync -> company + cap
FN->>DB: SELECT claim_line + case
FN->>DB: prior resolution (line, replace)?
Note over FN,DB: exists -> return idempotent, no re-post
FN->>L: currentAvgCost(variant, from_location)
Note over FN: replaceValue = qty * avg cost
FN->>K: createDocument(STOCK)<br/>stock -qty + Dr warranty_claim_expense / Cr inventory
K->>L: post stock-out + GL (amount_from_stock)
FN->>K: submitDocument(idempotency_key claims-resolve:line:replace)
K-->>FN: document id
FN->>DB: INSERT replacement_order (state closed, carryover)
FN->>DB: UPDATE line + case -> closed
FN->>DB: appendEvent claims.resolution.completed
FN-->>C: { ok, resolution }
หมายเหตุ
- จุดประสงค์: จัดการ warranty แบบผูก serial ตั้งแต่ลงทะเบียน (
register_warranty) โอนสิทธิ์ (transfer_warranty) รับเคลม (claim_intake) กัก RMA (rma_quarantine) จนถึงปิดเคส (resolve_claim) และเคลมคืน supplier (supplier_claim_back) — ทั้งหมด company-scoped ผ่านgetIdentityAsync. - Entitlement เป็น gate จริง:
claim_intakeตัดสินจากกฎclaim_date <= warranty_expiryเทียบ registration ล่าสุดของ serial; ผ่าน = caseaccepted, ไม่ผ่าน = case+linerejectedแล้ว throw 422 พร้อม snapshot ลงerp_claims_warranty_entitlement_check.triage_claimบล็อกเคสไม่มีสิทธิ์เว้นแต่ decision =reject. - Money-safety (subledger == GL): ทุกการขยับ stock ที่มีมูลค่าไปผ่าน kernel
createDocument/submitDocumentเท่านั้น.rma_quarantineเป็น transfer value-neutral (in-cost =currentAvgCostของ source, ไม่มี journal).restock_refurbclamp inbound cost ไม่ให้เกิน carrying (write down ได้อย่างเดียว) แล้วโพสต์ส่วนต่าง Drwarranty_claim_expense/ Crinventory.scrapและreplacerelieve inventory จริงพร้อม writeoff/expense offset. - Idempotency:
resolve_claimมี re-resolution guard ด้วย UNIQUE(claim_line, kind)(retry คืนของเดิม);replace/refund/creditยังฝัง deterministicidempotency_key(claims-resolve:<line>:<kind>) ให้ kernel replay โพสต์เดิมแทน double-post;restock_refurbเช็ค operation_group ซ้ำก่อน move. - Location invariants: hold ต้องเป็น
quality_hold/claim_cage; restock source = hold location ที่บันทึกตอน quarantine และปลายทางต้องเป็น sellable (site/warehouse/zone/bin); scrap ต้องเป็น location typescrap. กันของ strand หรือมูลค่าค้าง balance sheet. - Gotchas: ทุก action append เข้า
erp_claims_warranty_event_log(append-only, มีcustomer_visibleflag; มีแค่ intake accepted ที่ตั้ง 1). GET read surface จำกัด resource เป็น whitelist ของ 8 ตารางกัน SQL injection และต้อง capmanage/erp/finance/accounting.resolve_claimkind=replaceปิดเป็นclosed, ส่วน repair/refund/credit/reject/return_as_is ปิดเป็นresolved.