1.7 · สวัสดิการรักษาพยาบาล (WDHospital)
บทนี้อธิบาย flow การเบิกค่ารักษาพยาบาล — เป็น state machine 13 states ที่ซับซ้อนที่สุดในระบบ
ความแตกต่างจากการลา — WDHospital เก็บใน VTRC เอง (ไม่ได้ไปฝาก HRMI เป็น source of truth) และ approver เก็บในตาราง MasterApprovers ของ VTRC ด้วย
ความสัมพันธ์ที่เบิกได้
พนักงานเบิกให้ตัวเองหรือคนในความดูแลได้ — vtrc-api/api/src/config.js:392-429 (relationHrmi)
| Code | ความสัมพันธ์ | หมายเหตุ |
|---|---|---|
00 | ตัวเอง | self-claim |
10 | บิดา | |
20 | มารดา | |
70 | คู่สมรส | |
81 | บุตรคนที่ 1 | |
82 | บุตรคนที่ 2 | |
83 | บุตรคนที่ 3 | |
84 | บุตรคนที่ 4 | |
85 | บุตรคนที่ 5 |
policy "เบิกให้บุตรได้สูงสุด 5 คน" เป็น policy ที่ hardcode ใน code ผ่าน list นี้ — ถ้า HR อยากขยายเป็น 6 คน ต้องแก้ code ไม่ใช่แก้ MasterData
13-state machine
models/core/withdraw/hospital.js:94-97 — status enum ทั้งหมด
| Status | หมายถึง | เปลี่ยนจากไหน / โดยใคร |
|---|---|---|
DRAFT | แบบร่าง | ตอน create (hospital.js:1396) |
PENDING | รอตรวจสอบ | submit จาก DRAFT |
MOREINFO | ขอข้อมูลเพิ่ม | approver |
APPROVE | อนุมัติ รอโอนเงิน | approver level สุดท้าย (hospital.js:1508) |
REJECT | ไม่อนุมัติ | approver |
PAID | เงินเข้า (bank) — mark ด้วยมือ | HR/admin ตั้ง status PAID (ไม่ใช่ผลจาก KBANK import) |
PAIDCASH | เงินเข้า (เงินสด) | HR mark จ่ายสด |
CASH | รอจ่ายเงินสด | เลือก channel |
FAILED | KBANK ล้มเหลว | KBANK import — code 6, 7, 8, 10 |
SUCCESS | KBANK โอนสำเร็จ | KBANK import — code 9 → statusKcash.status = SUCCESS (label PAID / โอนสำเร็จ) |
CANCEL | ยกเลิก | หลายทาง |
CANCELDOC | ยกเลิกเอกสาร | HR |
EDIT | admin แก้หลังสร้าง | admin |
หมายเหตุ — code K-Cash 9 มี label PAID / โอนสำเร็จ แต่ค่าที่เขียนลง WDHospital.status คือ SUCCESS (config.js:508-511) — ไม่ใช่ status document PAID จาก import และ PAID ≠ alias ของ SUCCESS
PAIDCASH และ CASH ก็เช่นกัน — เป็น channel คู่ขนานกับ bank
State Diagram
┌─────────┐
│ DRAFT │ ← create (status เริ่มต้น)
└────┬────┘
│ submit
▼
┌─────────┐
┌───────►│ PENDING │◄─────────────┐
│ └────┬────┘ │
│ │ │
│ ├──► MOREINFO ──────┤ resubmit (พนักงานแก้)
│ │ │
│ ├──► REJECT │
│ │ │
│ ├──► EDIT (admin) ──┤
│ │ │
│ ▼ │
│ ┌─────────┐ │
│ │ APPROVE │ │
│ └────┬────┘ │
│ │ │
│ ├──► CASH ──► PAIDCASH
│ │ │
│ ├──► export KBANK │
│ │ │ │
│ │ ▼ │
│ │ WDExport batch │
│ │ │ │
│ │ ▼ │
│ │ KBANK process │
│ │ │ │
│ │ ├──► SUCCESS (code 9)
│ │ └──► FAILED ─┘
│ │ │
│ └──► CANCEL ────────┤
│ │
└─────────────────────────────────┘
(retry path)Approval Chain — MasterApprovers
ผู้อนุมัติ WDHospital เก็บใน VTRC ไม่ใช่ HRMI
models/core/masterData/masterApprovers.js:1-56
| Field | หน้าที่ |
|---|---|
approverId (UUID) | PK |
empCode | รหัสพนักงานของผู้อนุมัติ |
userId | FK → User |
orgCode | หน่วยงานที่ดูแล |
orgName | ชื่อหน่วยงาน |
isActive | 0/1 |
type | enum "MEDICAL" (ตอนนี้มีแค่ type นี้) |
createdBy / updatedBy | audit |
HR จัดการผ่านเมนู MasterApprovers — เพิ่ม/แก้/ปิด active ตาม orgCode
เมื่อ create WDHospital — อะไรเกิดขึ้นบ้าง
lib/controllers/withdraw/hospital.js:1357-1465
- บังคับ status
DRAFT(hospital.js:1396) — ไม่ใช่PENDINGทันที orderNo = 1- Generate
withdrawNoผ่านgetWithdrawNo()(running number) - ถ้า
orgCode == "88"→empType = "บำนาญ"(hospital.js:1388) อัตโนมัติ ไม่งั้นempType = "เจ้าหน้าที่" - Query
MasterApproversด้วย{ orgCode, isActive: 1, type: 'MEDICAL' } - ส่ง
WELFAREnotification ให้ผู้อนุมัติทุกคน title "รออนุมัติ" +redirect_path: /hospital/Confirm/{id}
ข้อสังเกต — notification redirect ไป /hospital/Confirm/ (role approver) ไม่ใช่ /hospital/ (role พนักงาน) ตาม redirectWDHospitalPath (wdHospital.js:170-173)
Field สำคัญใน WDHospital
models/core/withdraw/hospital.js:1-236
| Field | หน้าที่ |
|---|---|
wdHospitalId (UUID) | PK |
withdrawNo | เลขที่เอกสาร (running) |
withdrawOrder | ลำดับ |
documentNo | เลขเอกสารอ้างอิง |
relation | code ความสัมพันธ์ (00, 10, 20, 70, 81-85) |
totalWithdraw | ยอดขอเบิก |
totalCurrentWithdraw | ยอดที่อนุมัติจริง |
previousCurrentWithdraw | ยอดเบิกครั้งก่อน |
coaCodeName | เลขงบ (chart-of-accounts) |
hospitalName | ชื่อโรงพยาบาล |
hospitalBankAccountId | บัญชีธนาคารของโรงพยาบาล |
hospitalType | ประเภทโรงพยาบาล |
sicknessName / sicknessId | โรค |
patientType | ประเภทคนไข้ |
privateCase | กรณีผู้ป่วยส่วนตัว |
treatmentStartDate / EndDate | วันที่รักษา |
refDocument | เอกสารอ้างอิง |
noteApprove | หมายเหตุผู้อนุมัติ |
bank | KBANK หรือ OTHER |
cashFlg | flag จ่ายเงินสด |
payCashBy / payCashDate / effectivePayDate | เมื่อจ่ายสด |
importStatus / importLabel | ผล KBANK |
exportRefCode / wdExportId | batch export |
isJuristic | นิติบุคคล |
status | enum 13 states |
isHistory | 0 = current, 1 = snapshot ประวัติ |
Pre-check ก่อนจ่ายเงิน
checkPersonnelResignation(wdHospitalIds) (wdHospital.js:168)
ก่อน export หรือจ่าย — HR ตรวจว่าพนักงานที่จะจ่ายให้ "ลาออกแล้วหรือยัง"
ผลลัพธ์
type ResignationPersonnel {
status: String
empCode: [String]
withdrawNo: [String]
}HR เห็นในหน้าจอ → ตัดสินใจด้วยตัวเองว่าจะจ่ายหรือไม่ ระบบไม่ block อัตโนมัติ
Export ไป KBANK
flow การส่งออก batch จ่ายผ่านธนาคารกสิกรไทย (KBANK K-Cash)
- HR เลือก WDHospital ที่ status
APPROVEหลายรายการ - เรียก
createExportWDHospital(wdHospitalIds, years, payDate, totalExport, wdHospitalDatas) - ระบบสร้าง row ใน
WDExport(table tracking batch) - stamp
wdExportId+exportRefCodeในแต่ละ WDHospital - HR download zip ผ่าน
fetchUrlExportWdHospital
zip ประกอบด้วย 3 ไฟล์ (routes.js:776-811)
| File | Encoding | หน้าที่ |
|---|---|---|
${exportCode}_KBank_welfare.txt | TIS-620 | K-Cash payroll input |
${exportCode}_Smartcredit_welfare.txt | (default) | SmartCredit input |
${exportCode}_FMIS.xlsx | binary | FMIS accounting Excel |
เงื่อนไข — KBANK text ถูกสร้างเฉพาะเมื่อ length > 179 (routes.js:803)
การ import ผล KBANK
KBANK process ไฟล์เสร็จ → ส่งไฟล์ผลกลับมา → HR upload ผ่าน importUpdateStatus(file)
lib/controllers/withdraw/hospital.js:2160-2316
algorithm
- Parse ไฟล์ — row header (
header == 'h') ระบุexportCode, row อื่นเป็น detail - แต่ละ row — map
element.status(K-Cash code) ผ่านstatusKcash(config.js:488-519)
| K-Cash code | VTRC status | label / คำอธิบาย |
|---|---|---|
9 | SUCCESS | label PAID / โอนสำเร็จ — ไม่เขียน status PAID |
6 | FAILED | duplicate + stoppay |
7 | FAILED | cancelled |
8 | FAILED | stoppay |
10 | FAILED | unsuccessful credit |
- Validate ยอด —
totalCurrentWithdrawในไฟล์ต้องตรงกับ DB (hospital.js:~2230) - Update WDHospital
WDHospital.update({
importStatus: element.status,
status: statusByKcash.status, // SUCCESS หรือ FAILED
importLabel: statusByKcash.labelTH,
effectivePayDate: element.effectivePayDate
})- เขียน
WDHistoryrow + snapshot WDHospital (isHistory=1) - เมื่อ
wdExportData.totalExport == totalImport→WDExport.isImport = 1(batch ปิด)
Channel เงินสด (Cash)
ถ้า HR เลือกจ่ายเงินสดแทนผ่านธนาคาร — cashFlg = 1 และ status เป็น CASH หรือ PAIDCASH
| Field | ใช้ตอนไหน |
|---|---|
bank = 'OTHER' | ไม่ใช่ KBANK |
cashFlg = 1 | จ่ายสด |
payCashBy (UUID) | ใครจ่าย |
payCashDate | วันที่จ่าย |
effectivePayDate | วันมีผล |
flow นี้ไม่ผ่าน KBANK — HR mark จ่ายด้วยมือในหน้า backoffice
Cancel export
cancelExportWDHospital (wdHospital.js:398)
HR สามารถ cancel batch export ทั้ง batch ได้ ถ้ายังไม่ import ผล
- WDHospital ทุกตัวใน batch reset status กลับเป็น
APPROVE(hospital.js:2393) WDExport.isCancel = 1(export.js:26-30)
ประเภทค้นหาใน backoffice
BackOfficeSeachType enum (wdHospital.js:611-618)
| Code | view |
|---|---|
ALLWDLIST | ทั้งหมด |
PAYWDLIST | รอโอน/จ่าย |
FAILEDWDLIST | ล้มเหลว |
SearchDetailType enum (wdHospital.js:602-609)
| Code | role |
|---|---|
DETAIL | พนักงานดูของตัวเอง |
CONFIRM | approver ดูที่ต้องอนุมัติ |
BACKOFFICE | HR |
Associations — relation กับตารางอื่น
models/core/withdraw/hospital.js:247-259
WDHospital
├── hasMany WDSlip (ใบเสร็จหลายใบ)
├── hasMany WDHospitalDocument (เอกสารอื่น)
├── hasMany Approver
├── hasMany MasterApprover (by orgCode)
├── belongsTo WDHistory
├── belongsTo WDExport
├── belongsTo Sickness (2 alias)
├── belongsTo Hospital (2 alias)
└── belongsTo HospitalBankAccountWDSlip สำคัญ — แต่ละ WDHospital มีได้หลายใบเสร็จ และยอดเบิก = ผลรวมของ slip ทั้งหมด
รายงาน — PDF + Excel
lib/controllers/withdraw/hospital.template.js (imported at routes.js:26) — template ทั้งหมด
| Query | Template |
|---|---|
fetchUrlFailPaymentPDF | failPaymentReportTemplate |
fetchUrlAllWithdrawPDFReport | sumOverveiwReportTemplate + variants |
fetchUrlWDHospitalApproverPDFReport | sumCoAReportTemplate ฯลฯ |
fetchUrlWDHospitalPaidPDFReport | sumWDHospitalPaidTemplate |
template แบ่งตามมุมมอง
- by chart-of-accounts (
sumCoAReportAllOrgTemplate,sumCoAReportTemplate) - by division (
sumDivisionReportTemplate) - by organization (
sumOrganizeReportTemplate) - by person (
sumPersonalReportTemplate) - overview (
sumOverveiwReportTemplate) - paying prepare (
sumPayingPrepareTemplate)
รายละเอียดเพิ่มเติมใน บท 1.14
Checklist ตอน debug
| อาการ | สาเหตุ |
|---|---|
| "อนุมัติแล้วไม่เห็นเงิน" | ยังไม่ export KBANK หรือ KBANK ยังไม่ import |
| "KBANK ตีก" | K-Cash code 6, 7, 8, 10 — ดู importLabel ใน WDHospital |
| "ยอดในไฟล์ไม่ตรง DB" | import ปฏิเสธ (hospital.js:~2230) |
| "หา approver ไม่ได้" | MasterApprovers.isActive = 0 หรือไม่มี row สำหรับ orgCode นี้ |
| "สถานะ APPROVE แต่ export ไม่ได้" | wdExportId ติด batch ที่ isCancel = 0 อยู่ |
| "พนักงานลาออก แต่ยังโอนได้" | checkPersonnelResignation แค่ flag ไม่ block |