Insurance Billing (فوترة التأمين)
The insurance billing system provides end-to-end insurance claim management: applying insurance to lab requests, auto-calculating patient/insurance shares, generating split invoices, and monthly aggregation for batch settlement with insurance companies.
Insurance Billing Workflow
Coverage Types
Percentage Coverage
Insurance pays a percentage of the test price. Patient pays the remainder.
| Field | Example | Description |
|---|---|---|
coverage_type | percentage | Type indicator |
default_coverage_value | 80 | Insurance covers 80% |
| Test price: 100 | Insurance: 80, Patient: 20 | Calculated split |
Fixed Copay
Patient pays a fixed amount per test. Insurance covers the rest.
| Field | Example | Description |
|---|---|---|
coverage_type | fixed_copay | Type indicator |
default_coverage_value | 15 | Patient pays 15 per test |
| Test price: 100 | Insurance: 85, Patient: 15 | Calculated split |
Price Resolution Priority
When calculating insurance prices, the system follows this priority chain:
- Contract Investigation -- Explicit
approved_price,patient_share,insurance_shareonlab_insurance_contract_investigations - Contract Price List -- Price from the contract's linked
price_list_id - Investigation Default -- The investigation's base
pricefield
Max Coverage Cap
If max_coverage_per_visit is set, the total insurance amount is capped. When the cap is reached, excess is redistributed proportionally to patient shares.
Example: 2 tests at 100 and 200, 80% coverage, cap at 100:
- Without cap: insurance = 240, patient = 60
- With cap: insurance = 100, patient = 200 (proportionally redistributed)
Insurance on Requests
Request Insurance Fields
| Field | Type | Description |
|---|---|---|
insurance_contract_id | FK | Applied insurance contract |
insurance_approval_number | string | Prior authorization number |
insurance_status | enum | pending, approved, rejected, claimed |
coverage_percentage | decimal | Resolved coverage percentage |
patient_share_total | decimal | Total patient share |
insurance_share_total | decimal | Total insurance share |
Per-Investigation Insurance Fields
| Field | Type | Description |
|---|---|---|
insurance_price | decimal | Resolved price for this investigation |
patient_share | decimal | Patient pays this amount |
insurance_share | decimal | Insurance pays this amount |
API Endpoints
Insurance on Requests
| Method | Endpoint | Description | Permission |
|---|---|---|---|
POST | /api/lis/requests/{id}/apply-insurance | Apply insurance to a request | lis.requests.update |
POST | /api/lis/requests/{id}/remove-insurance | Remove insurance from a request | lis.requests.update |
POST | /api/lis/requests/{id}/recalculate-insurance | Recalculate insurance shares | lis.requests.update |
Invoice Generation
| Method | Endpoint | Description | Permission |
|---|---|---|---|
POST | /api/lis/invoices/generate | Generate invoice(s) from request | lis.insurance-invoices.generate |
Monthly Insurance Invoices
| Method | Endpoint | Description | Permission |
|---|---|---|---|
GET | /api/lis/insurance-invoices/pending-aggregation | List pending aggregations | lis.insurance-invoices.monthly.view |
GET | /api/lis/insurance-invoices/monthly | List monthly invoices | lis.insurance-invoices.monthly.view |
GET | /api/lis/insurance-invoices/monthly/{id} | Show monthly invoice | lis.insurance-invoices.monthly.view |
POST | /api/lis/insurance-invoices/generate-monthly | Generate monthly aggregate | lis.insurance-invoices.monthly.generate |
Request / Response Examples
Apply Insurance to a Request
bash
curl -X POST /api/lis/requests/1/apply-insurance \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"insurance_contract_id": 1,
"insurance_approval_number": "AUTH-2026-001"
}'dart
final response = await dio.post('/api/lis/requests/1/apply-insurance', data: {
'insurance_contract_id': 1,
'insurance_approval_number': 'AUTH-2026-001',
});Generate Split Invoices
bash
curl -X POST /api/lis/invoices/generate \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"request_id": 1}'dart
final response = await dio.post('/api/lis/invoices/generate', data: {
'request_id': 1,
});
// Returns: { patient_invoice: {...}, insurance_invoice: {...} }
// Or for non-insured: { invoice: {...} }Generate Monthly Aggregate
bash
curl -X POST /api/lis/insurance-invoices/generate-monthly \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"insurance_contract_id": 1,
"month": "2026-03"
}'dart
final response = await dio.post('/api/lis/insurance-invoices/generate-monthly', data: {
'insurance_contract_id': 1,
'month': '2026-03',
});Monthly Insurance Invoice Attributes
| Field | Type | Description |
|---|---|---|
id | integer | Primary key |
insurance_contract_id | FK | Insurance contract |
partner_id | FK | BusinessPartner |
month | string(7) | Period (YYYY-MM) |
aggregate_invoice_id | FK | Generated aggregate invoice |
claims_count | integer | Number of individual invoices |
total_patient_amount | decimal | Sum of patient shares |
total_insurance_amount | decimal | Sum of insurance shares |
total_amount | decimal | Grand total |
status | enum | pending, generated, posted, paid |
generated_at | datetime | When generated |
generated_by | FK | User who generated |
Business Rules
- Split invoicing -- Insured requests produce 2 invoices (patient + insurance); non-insured produce 1 standard invoice.
- No duplicate generation -- A request can only have invoices generated once. Attempting again returns an error.
- Doctor commissions -- Only calculated on
standardandpatient_invoicetypes, never oninsurance_invoice(prevents double-counting). - Insurance accounting -- Insurance invoices use the contract's
insurance_receivable_account_id(DR) andrevenue_account_id(CR) for journal entries. - Monthly uniqueness -- Only one monthly aggregate per (company, contract, month) combination.
- Aggregation scope -- Only
postedinsurance invoices are eligible for monthly aggregation. - Related invoices -- Patient and insurance invoices are cross-linked via
related_invoice_id.