medOS ultra

Revenue Collection Progression

3-tab revenue-collection pipeline + settlement workspace, state machines, realtime channels, edge functions.

14 min read diagramsUpdated 2026-06-14docs/architecture/revenue-collection-progression-contract.md

⚠️ Correction (2026-06-14, audit): This doc’s claim elsewhere that “/revenue-collection route is DEAD — workspace lives at /revenue-settlement” is stale. The /revenue-collection route is LIVE (web/src/routes.tsx:407) and wired to real SalesOrder data (commit b41c5e897). What is actually dead is its Supabase view tier (useReceivablesUnified is called with client:null), not the route. See revenue-loop-flow-audit.md §6. Original content below is unchanged.

Central contract for the 3-stage revenue collection pipeline: แก้ไขกลุ่มลูกหนี้ → นำข้อมูลออก → บันทึกใบเรียกเก็บ (REP)

Status: Phase 1 Shipped + Realtime Audit — 2026-05-20


1. Entity Model

SalesOrder (MongoDB — write truth)

The single entity that flows through all 3 stages. Each visit/encounter produces one SalesOrder. The claimStatus field drives which tab the row appears in.

SalesOrder {
  _id:              ObjectId
  patient:          ObjectId → Patient
  encounter:        ObjectId → Encounter
  encounterClass:   'OPD' | 'IPD'

  // ── Financial ──
  payor:            ObjectId → Payor          // สิทธิการรักษา
  payorPlan:        ObjectId → PayorPlan      // แผนสิทธิย่อย
  payorSchema:      ObjectId → PayorSchema    // กองทุน
  mainHospital:     ObjectId → Hospital       // HC หลัก
  subHospital:      ObjectId → Hospital       // HC รอง
  totalAmount:      Number                    // ยอดเงินรวม
  claimAmount:      Number                    // ยอดเบิก
  paidAmount:       Number                    // ชำระแล้ว

  // ── Progression ──
  claimStatus:      ClaimStatus               // ← drives tab placement
  debtorGroup:      String                    // กลุ่มลูกหนี้ (set in stage 1)
  claimedSupervised: ObjectId → User          // ผู้รับผิดชอบ (coder)
  coder:            ObjectId → User

  // ── Timestamps ──
  visitDate:        Date
  dischargeDate:    Date
  billClosedAt:     Date | null               // ปิดบัญชี timestamp
  createdAt:        Date
  updatedAt:        Date
}

RevenueCollection (MongoDB — write truth)

Created in stage 3 when claim invoices are finalized. One RevenueCollection groups multiple SalesOrders into a single invoice document (ใบเรียกเก็บ).

RevenueCollection {
  _id:              ObjectId
  docNo:            String                    // เลขที่เอกสาร (INV-2569-XXXXX)
  salesOrderRef:    ObjectId[] → SalesOrder[] // grouped encounters
  totalClaimAmount: Number
  status:           'Draft' | 'Confirmed' | 'Exported' | 'Sent' | 'Settled'
  periodStart:      Date
  periodEnd:        Date
  createdBy:        ObjectId → User
  createdAt:        Date
  updatedAt:        Date
}

2. ClaimStatus Enum — The Progression Engine

┌──────────┐    ┌──────────┐    ┌───────────┐    ┌──────────────────┐
│ Prepare  │───▶│ Pending  │───▶│ Reviewing │───▶│ RevenueCollection│
│          │    │          │    │           │    │ (separate entity) │
│ Tab 1    │    │ Tab 2    │    │ Tab 3     │    │ Tab 3 (saved)    │
│ แก้ไขกลุ่ม│    │ นำข้อมูลออก │    │ รอบันทึก   │    │ บันทึกแล้ว        │
└──────────┘    └──────────┘    └───────────┘    └──────────────────┘
ClaimStatus Tab Component Description (TH)
Prepare แก้ไขกลุ่มลูกหนี้ฯ (Tab 1) MedicalDebtorsGroup กำหนดกลุ่มลูกหนี้ + ตรวจข้อมูล
Pending นำข้อมูลออก (Tab 2) InvoiceRecord ส่งออก 16 แฟ้ม + สร้างใบเรียกเก็บ
Reviewing บันทึกใบเรียกเก็บ (Tab 3) AwaitInvoiceContent รายการรอบันทึกเข้าใบเรียกเก็บ
(saved) บันทึกใบเรียกเก็บ (Tab 3) SavedInvoiceContent ใบเรียกเก็บที่บันทึกแล้ว

3. Tab ↔ Component ↔ API Mapping

Tab 1: แก้ไขกลุ่มลูกหนี้ค่ารักษาพยาบาล

Component: MedicalDebtorsGroup.tsx Query: listAllSaleOrder({ claimStatus: 'Prepare' }) Sandbox equivalent: Fdh16FileExportTarget (AR group editor)

Actions available:

Action API Transition
Assign debtor group (กลุ่มลูกหนี้) updateBulkClaimSalesOrder({ salesOrders, debtorGroup }) stays Prepare
Export 16 แฟ้ม exportSalesOrder({ encounterIds }) stays Prepare
Move to นำข้อมูลออก updateBulkClaimSalesOrder({ salesOrders, claimStatus: 'Pending' }) Prepare → Pending

Sub-tabs:

  • ทั้งหมด (all) — TSubTabMidicalDebtor.ALL
  • รายการรอบันทึก (partial) — TSubTabMidicalDebtor.PARTIAL
  • สรุปตามสิทธิ (by insurance scheme) — TSubTabMidicalDebtor.SUMMARY_SCHEME
  • สรุปตามกลุ่มลูกหนี้ (by debtor group) — TSubTabMidicalDebtor.SUMMARY_DEBTOR_GROUP

Bulk Edit Bar (shipped 2026-05-20): When rows are selected via checkbox, a sticky bar appears above the table with:

  • กลุ่มลูกหนี้ dropdown (same AR_GROUPS list)
  • “กำหนดกลุ่ม” apply button → calls updateBulkClaimSalesOrder({ salesOrders, debtorGroup })
  • Dirty count chip + cancel button
  • Dirty rows highlighted yellow via parse condition (row) => row._dirty

Inline Per-Row Editing (shipped 2026-05-20): Each row has an inline `` dropdown in the กลุ่มลูกหนี้ column:

  • Red border when unassigned ((ไม่ระบุ))
  • Yellow background when dirty (changed but not yet navigated away)
  • Calls updateBulkClaimSalesOrder({ salesOrders: [id], debtorGroup }) immediately on change

Additional Columns (shipped 2026-05-20):

  • HC หลัก — mainHospital?.name (Hospital main contractor)
  • HC รอง — subHospital?.name (Hospital sub-contractor)
  • กลุ่มลูกหนี้ — inline `` (see above)

Summary Sub-tabs (shipped 2026-05-20):

  • สรุปตามสิทธิ: Groups by payorPlan.name, shows count / totalAmount / unassigned count (red chip)
  • สรุปตามกลุ่มลูกหนี้: Groups by debtorGroup, shows count / totalAmount, red highlight row for (ไม่ระบุ)

Tab 2: นำข้อมูลออก (InvoiceRecord)

Component: InvoiceRecord.tsx (confusing name — it’s the export stage, not invoice recording) Query: listAllSaleOrder({ claimStatus: 'Pending' })

Sub-tabs:

Sub-tab Component Purpose
รายการรอบันทึก AwaitInvoiceContent Select rows to stage for export
นำข้อมูลออก ExportInvoiceContent Transfer list → review → export files
รายการที่บันทึกแล้ว SavedInvoiceContent Previously saved exports

Actions available:

Action API Transition
Stage selected rows (local state: stagedIds) stays Pending
Export staged rows to files exportSalesOrder({ encounterIds }) stays Pending
Create revenue collection (ใบเรียกเก็บ) createRevenueCollection(payload) Pending → Reviewing
Import REP bill from Excel DialogImportRepBill bulk import

Tab 3: บันทึกใบเรียกเก็บเงิน (REP / ใบเรียกเก็บ)

Component: InvoiceRecord.tsx → sub-tabs use claimReviewingQuery + revenueCollectionQuery Query: listAllSaleOrder({ claimStatus: 'Reviewing' }) + listAllRevenueCollection() Sandbox equivalent: RevenueSettlementTarget (claim invoice grid)

Actions available:

Action API Transition
Record invoice createRevenueCollection(payload) creates RevenueCollection
Download/print invoice reportEClaim() read-only
Cancel revenue collection cancelRevenueCollection() reverts
Update bulk status updateBulkStatusRevenueCollection({ status }) Confirmed/Sent/Settled

4. API Service Inventory

All services in web/src/services/ever-financial/:

Service Function Used By
saleOrder.service listAllSaleOrder(filters) All 3 tabs (different claimStatus)
saleOrder.service updateBulkClaimSalesOrder({ salesOrders, claimStatus }) Tab 1 → 2 transition, bulk debtor group assign
saleOrder.service exportSalesOrder({ encounterIds }) Tab 1 + Tab 2 (16 แฟ้ม export)
saleOrder.service createRevenueCollection(payload) Tab 2 → 3 transition (create ใบเรียกเก็บ)
saleOrder.service updateBulkStatusRevenueCollection({ status }) Tab 3 status flow
saleOrder.service listAllRevenueCollection(filters) Tab 3 saved invoices
accountReceivable.service reportEClaim() Tab 3 E-Claim report

5. Sandbox ↔ Production Component Map

Sandbox Target Production Component Stage Status
Fdh16FileExport MedicalDebtorsGroup Tab 1: แก้ไขกลุ่มลูกหนี้ Mock data — features now ported to production
ArGroupEditor (next-gen prototype) Tab 1: แก้ไขกลุ่มลูกหนี้ Modern row-grouping, auto-assign, batch queue, filter chips, keyboard shortcuts
RevenueSettlement InvoiceRecord + SavedInvoiceContent Tab 2+3: นำข้อมูลออก + ใบเรียกเก็บ Mock data only — no API wiring

6. Filter Contract (shared across all tabs)

All 3 tabs share a single TFilterSearch state managed in MainTab.tsx:

{
  search:           string       // HN / ชื่อ / เลขที่เอกสาร
  fromDate:         Date | null  // วันจำหน่าย เริ่ม
  toDate:           Date | null  // วันจำหน่าย ถึง
  payor:            Payor        // สิทธิ/Payor (top-level)
  payorPlan:        PayorPlan[]  // แผนย่อย (ประกันสังคม HD, ตรวจสุขภาพ, etc.)
  payorSchema:      PayorSchema  // กองทุน
  mainHospital:     Hospital     // HC หลัก
  subHospital:      Hospital     // HC รอง
  clinic:           Clinic       // แผนก
  subClinic:        SubClinic    // แผนกย่อย
  claimedSupervised: User[]      // ผู้ตรวจ/coder
}

7. File Inventory (production code)

packages/rcm-kit/src/financial/components/
├── MainTab.tsx                          # Top-level 3-tab container
├── interface.ts                         # TTabValue, TSubTabValue, TFilterSearch, enums
├── useFetchData.ts                      # All queries (Prepare/Pending/Reviewing/Revenue)
├── style.tsx                            # Styled components
├── Component.tsx                        # FilterGroup, CustomButtonSplit
├── RowTableFinancial.tsx                # Shared table row renderer
├── MedicalDebtorsGroup.tsx              # Tab 1: แก้ไขกลุ่มลูกหนี้
├── InvoiceRecord.tsx                    # Tab 2: นำข้อมูลออก (sub-tab container)
├── invoice-record-content/
│   ├── AwaitInvoiceContent.tsx          # Sub: รายการรอบันทึก
│   ├── ExportInvoiceContent.tsx         # Sub: นำข้อมูลออก (staged transfer)
│   ├── SavedInvoiceContent.tsx          # Sub: รายการที่บันทึกแล้ว
│   ├── SettleAccountContent.tsx         # Settlement/reconciliation
│   ├── FileUpload.tsx                   # File upload helper
│   └── useDownlaodStreamFile.tsx        # Download stream helper
├── dialog/
│   ├── DialogFinancialDetail.tsx        # Detail view dialog
│   ├── DialogEditBill.tsx               # Edit bill dialog
│   ├── DialogCustomExport.tsx           # Custom export format dialog
│   ├── dialog-import-rep-bill/          # REP bill import (Excel)
│   │   ├── DialogImportRepBillMain.tsx
│   │   ├── DialogImportRepBill.tsx
│   │   ├── DialogImportStatement.tsx
│   │   └── DialogImportUcExcel.tsx
│   └── content/
│       └── InvoiceRecord.tsx            # Dialog content for invoice detail
├── revenue-settlement/                  # Extended settlement workspace
│   ├── landing-page.tsx
│   ├── workspace-page.tsx
│   └── components/                      # 25+ panel components
│       ├── ClaimInvoicePanel.tsx
│       ├── RepManagementPanel.tsx
│       ├── RepImportPanel.tsx
│       ├── DebtorGroupReviewPanel.tsx
│       ├── ARSettlementPanel.tsx
│       ├── ClaimReconciliationPanel.tsx
│       └── ...
└── revenue-collection-dashboard/
    ├── RevenueCollectionDashboard.tsx
    └── MonthlyTrendChart.tsx

8. Progression Invariants

  1. A SalesOrder can only be in one ClaimStatus at a time — it appears in exactly one tab.
  2. Debtor group (กลุ่มลูกหนี้) must be assigned before moving Prepare → Pending — Tab 1 validates this.
  3. Export (16 แฟ้ม) can happen at any stageexportSalesOrder doesn’t change ClaimStatus.
  4. RevenueCollection creation transitions Pending → Reviewing — the SalesOrder gains a salesOrderRef backlink.
  5. Filters are shared — changing a payor filter in Tab 1 persists when switching to Tab 2.
  6. Pagination is per-tab — each tab has its own page/pageSize in TFilterSearch.
  7. claimedSupervised scoping — Tab 2 and 3 default to showing only the current user’s assignments unless “ทั้งหมด” is selected.

9. Naming Clarification

Legacy (HOSxP) Production Component Name Enum Value What it does
แก้ไขกลุ่มลูกหนี้ฯ MedicalDebtorsGroup EDIT_MEDICAL_DEBTORS_GROUP Assign กลุ่มลูกหนี้ to Prepare-status SalesOrders
นำข้อมูลออก InvoiceRecord (misleading) REMOVE_RECORD (misleading) Stage + export + move to Reviewing
บันทึกใบเรียกเก็บ / REP (shared across sub-tabs) INVOICE_RECORD Create RevenueCollection records

Known naming issues:

  • TTabValue.REMOVE_RECORD should be EXPORT_DATA — “remove” is misleading
  • InvoiceRecord.tsx handles the export stage, not invoice recording — confusing because the dialog content file is also called InvoiceRecord.tsx
  • claimPedingQuery has a typo (“Peding” → “Pending”)

10. What the Sandbox Targets Prove

Sandbox Target Proves Missing vs Production
Fdh16FileExport UI layout, inline debtor group editing, checkbox+bulk, 14 insurance schemes, HC column, summary tabs, dirty tracking (Features ported to production MedicalDebtorsGroup.tsx on 2026-05-20)
ArGroupEditor Row grouping (collapsible by scheme/debtor), auto-assign (scheme→group mapping), batch save queue with undo, filter chips with badges, progress bar (assignment %), keyboard shortcuts (Ctrl+S/A/Esc), sortable columns, sticky bottom action bar, realtime connection indicator Production wiring: listAllSaleOrder + updateBulkClaimSalesOrder, Payor/PayorPlan autocomplete, Supabase realtime channels
RevenueSettlement Claim invoice grid, status chips, bulk add dialog, import Excel, drag-select, per-row actions Real createRevenueCollection / updateBulkStatusRevenueCollection, E-Claim export, settlement flow

11. Integration Plan (merge sandbox → production)

Phase 1: Enhance Tab 1 (แก้ไขกลุ่มลูกหนี้) — SHIPPED 2026-05-20

  • [x] Port inline debtor group dropdown from Fdh16FileExport sandbox into MedicalDebtorsGroup.tsx
  • [x] Add HC หลัก / HC รอง columns to RowTableFinancial when type === 'medical-expenses'
  • [x] Wire bulk debtor group assign to updateBulkClaimSalesOrder
  • [x] Add summary-by-scheme and summary-by-debtor-group sub-tabs
  • [x] Bulk edit bar (select rows → apply group)
  • [x] Dirty row tracking with yellow highlight
  • [x] Red border on unassigned กลุ่มลูกหนี้

Phase 1.5: Next-Gen Prototype (ArGroupEditor sandbox) — IN PROGRESS

  • [x] Row grouping with collapsible headers (by scheme or debtor group)
  • [x] Auto-assign mapping (insurance scheme prefix → debtor group)
  • [x] Batch save queue with pending changes array + undo
  • [x] Filter chips with active badge counts
  • [x] Progress bar showing assignment completion %
  • [x] Keyboard shortcuts (Ctrl+S save, Ctrl+A auto-assign, Esc clear)
  • [x] Sortable columns (6 fields)
  • [x] Sticky bottom action bar with batch save/discard/undo
  • [x] Realtime connection indicator (mock)
  • [ ] Wire to production APIs
  • [ ] Wire Supabase realtime channels

Phase 2: Enhance Tab 2 (นำข้อมูลออก)

  • Port staged transfer UX from ExportInvoiceContent improvements in sandbox
  • Add 16 แฟ้ม export progress indicator
  • Wire FDH upload integration

Phase 3: Enhance Tab 3 (REP / ใบเรียกเก็บ)

  • Port claim invoice grid from RevenueSettlement sandbox into AwaitInvoiceContent / SavedInvoiceContent
  • Add import Excel dialog from sandbox
  • Wire settlement reconciliation flow

12. Route Status

The /revenue-collection route does NOT exist in routes.tsx.

Route Status File
/revenue-collection DEAD — no entry in routes.tsx Container exists at src/containers/revenue-collection/index.tsx
/revenue-settlement LIVE routes.tsx:346
/revenue-settlement-legacy LIVE routes.tsx:347
/revenue-settlement-command-center LIVE routes.tsx:348
/revenue-summary-report LIVE routes.tsx:349

What happened:

  • src/containers/revenue-collection/index.tsx renders `` (the 3-tab container)
  • src/config/page-registry.ts:582-588 has cashier-list-patient-revenue at /cashier/list-patient-revenue-collection but references a _refactored-pages/ file that doesn’t exist
  • Multiple docs reference /revenue-collection (command-center, UAT delivery, IPD UAT guides) — all dead links
  • The production 3-tab flow is fully built in rcm-kit/financial/components/ but has no way to reach it from the app

To fix: Register /revenue-collection in routes.tsx pointing to containers/revenue-collection/index.tsx, or add a page-registry.ts entry with a real component path.


13. Supabase Realtime Infrastructure

Existing Channels (Financial/Revenue/Claims)

Channel Name Table Location Purpose
rcm-claim-batches rcm_claim_batch services/ever-financial/rcmClaim.service.ts Claim batch status (defined but NOT subscribed in any UI)
rcm-correction-queue rcm_correction_queue services/ever-financial/rcmClaim.service.ts Correction queue (defined but NOT subscribed in any UI)
rcm-financial-alerts rcm_financial_alert services/ever-financial/rcmClaim.service.ts Financial alerts (defined but NOT subscribed in any UI)
eclaim-government-sync (gov eClaim) services/ever-financial/rcmClaim.service.ts Government eClaim sync
eclaim-statements (statements) services/ever-financial/rcmClaim.service.ts Statement imports
rep-response-realtime rcm_rep_response revenue-settlement/RepManagementPanel.tsx REP status changes (A/C/D/P), auto-refresh on import
correction-queue-realtime rcm_correction_queue revenue-settlement/CorrectionQueuePanel.tsx Correction item lifecycle
discharge-alert-billing department_queues (billing) revenue-settlement/useDischargeAlert.ts Discharged encounters → billing alert
price-update-{encounterId} encounter_journey_cache clinical-dashboard/hooks/useRealtimeFinancials.ts Per-encounter financial summary updates
billing-queue-waiting department_queues (billing) service-kit/queue-management-opd/.../QueueListService.js Billing queue changes

Edge Functions in the Pipeline

Function Location Trigger Financial Impact
encounter-orchestrator infrastructure/medbase/functions/ hospital_events INSERT Updates encounter_journey_cache.financial_summary, manages billing queue rows
rcm-rule-engine infrastructure/medbase/functions/ (invoked) Evaluates encounter financials, persists alerts to rcm_financial_alert
rcm-reconcile-discharged-unsettled infrastructure/medbase/functions/ (cron/invoke) Safety-net for IPD discharge→settle chain failures
eclaim-connector infrastructure/medbase/functions/ (invoke) Syncs government eClaim REP responses, emits CLAIM_SETTLED
gold-layer-refresh infrastructure/medbase/functions/ (invoke) Aggregates financials to reporting layer

Hospital Events (Financial)

Event Type Source Downstream
hospital.financial.updated NestJS SalesOrderControllerMixin Orchestrator → encounter_journey_cache.financial_summary → realtime fires
CLAIM_SETTLED eclaim-connector (on REP A-case) Triggers AR update (MongoDB)
CODING_COMPLETED coder.controller.mixin Triggers RCM validation
clinical.encounter.discharged encounter.controller.mixin Fire-and-forget → settleAccountByEncounter → reconcile safety net

What’s Missing (Gaps)

  1. No sales-orders-realtime channel — SalesOrder status changes (Prepare→Pending→Reviewing) are NOT subscribed in the UI. Only the projected financial_summary in cache is watched via useRealtimeFinancials. A direct channel on sales_orders (if/when it exists in Supabase) would let the Tab 1/2/3 tables auto-refresh when another user changes a row’s claimStatus.

  2. rcm-claim-batches defined but never subscribed — The channel exists in rcmClaim.service.ts but no component listens to it. The claim batch dashboard would benefit from auto-refresh.

  3. No rcm_financial_alert → UI worklist subscription — Alerts are persisted by the rule engine but the coder worklist reads them via REST polling, not realtime. A useRealtimeFinancialAlerts() hook is needed.

  4. No presence tracking for billing staff — Other departments (OR, IPD ward) have presence channels. Billing operators can’t see who is working on which account.

  5. No CLAIM_SETTLED → UI feedback loop — eclaim-connector emits CLAIM_SETTLED but there’s no edge function that broadcasts confirmation back to the RepManagementPanel. The panel relies on polling listRepResponses().

  6. No concurrent-edit awareness on correction queueCorrectionQueuePanel subscribes to row changes but no presence/lock mechanism prevents two coders from editing the same correction item.

  7. No hospital_events subscription in frontend — The canonical event log is consumed only by edge functions. A useHospitalEventsRealtime() hook for subscribing to CODING_COMPLETED, CLAIM_SETTLED, etc. would enable reactive UI updates.

Proposed New Hooks

Hook Channel Table Purpose
useSalesOrderRealtime() sales-order-{tab} sales_orders (when projected) Auto-refresh Tab 1/2/3 on claimStatus changes
useRealtimeFinancialAlerts() rcm-financial-alerts rcm_financial_alert Live alert feed in coder worklist
useClaimBatchRealtime() rcm-claim-batches rcm_claim_batch Auto-refresh batch status dashboard
useHospitalEventsRealtime(types) hospital-events-{filter} hospital_events Generic subscription to financial event types
useRealtimeCorrectionAssignment() correction-presence (presence) Presence + locking for correction items

14. AR Group Constants

Canonical debtor group list (exported from RowTableFinancial.tsx as AR_GROUPS):

export const AR_GROUPS = [
  '(ไม่ระบุ)',                    // Unassigned (default)
  'ลูกหนี้ สปสช.',               // NHSO (สปสช.)
  'ลูกหนี้ ประกันสังคม',          // Social Security (ประกันสังคม)
  'ลูกหนี้ กรมบัญชีกลาง',        // Comptroller General (กรมบัญชีกลาง)
  'ลูกหนี้ อปท.',                // Local Government (อปท.)
  'ลูกหนี้ พ.ร.บ.',              // Motor Vehicle Act (พ.ร.บ.)
  'ลูกหนี้ บริษัทประกัน',         // Private Insurance
  'ลูกหนี้ ผู้ป่วยจ่ายเอง',       // Self-pay
  'ลูกหนี้ อื่นๆ',                // Other
];

Auto-assign mapping (from ArGroupEditorTarget.tsx — not yet in production):

Insurance Scheme Prefix → Debtor Group
UC, สิทธิ UC, บัตรทอง, สปสช ลูกหนี้ สปสช.
SSS, ประกันสังคม ลูกหนี้ ประกันสังคม
CSMBS, กรมบัญชีกลาง, ข้าราชการ ลูกหนี้ กรมบัญชีกลาง
อปท, อบต, อบจ, เทศบาล ลูกหนี้ อปท.
พ.ร.บ, พรบ, Motor ลูกหนี้ พ.ร.บ.
ประกัน, Insurance, AIA, เมืองไทย, กรุงเทพ, Prudential ลูกหนี้ บริษัทประกัน
Self, จ่ายเอง, Cash ลูกหนี้ ผู้ป่วยจ่ายเอง
Ask Anything