Skip to content

Lab Invoices (فواتير المختبر)

Lab Invoices handle the billing for laboratory services. Each invoice is linked to a lab request and patient, supports insurance contract integration, and follows a lifecycle from draft through posting (with journal entry creation) to payment or cancellation.

Entity Attributes

FieldTypeRequiredDescription
idintegerautoPrimary key
invoice_numberstringautoAuto-generated invoice number
lab_request_idFKyesAssociated lab request
patient_idFKyesBilled patient
datedateyesInvoice date
statusenumautodraft, posted, partially_paid, paid, cancelled
subtotaldecimal(12,3)autoSum of item prices
discount_amountdecimal(12,3)autoTotal discounts
tax_amountdecimal(12,3)autoTotal tax
totaldecimal(12,3)autoNet total
amount_paiddecimal(12,3)noAmount received
balance_duedecimal(12,3)autoTotal minus amount paid
insurance_contract_idFKnoApplied insurance contract
insurance_amountdecimal(12,3)noInsurance share
patient_amountdecimal(12,3)noPatient share
journal_entry_idFKautoCreated on post
cancel_journal_entry_idFKautoCreated on cancel
notestextnoInvoice notes
branch_idFKnoBranch
posted_byFKautoUser who posted
posted_atdatetimeautoPost timestamp
cancelled_byFKautoUser who cancelled
cancelled_atdatetimeautoCancel timestamp
cancellation_reasonstringnoReason for cancellation
invoice_typeenumautostandard, patient_invoice, insurance_invoice
related_invoice_idFKnoCross-linked invoice (patient/insurance pair)
insurance_company_namestringnoDenormalized insurance company name
insurance_company_name_arstringnoDenormalized insurance company name (Arabic)
partner_idFKnoBusinessPartner for insurance invoices

Invoice Item Attributes

FieldTypeRequiredDescription
lab_invoice_idFKyesParent invoice
investigation_idFKyesBilled investigation
descriptionstringnoItem description
pricedecimal(12,3)yesUnit price
discountdecimal(12,3)noItem discount
taxdecimal(12,3)noItem tax
net_amountdecimal(12,3)autoPrice - discount + tax

Status Workflow

API Endpoints

MethodEndpointDescriptionPermission
GET/api/lis/invoicesList invoices (paginated)lis.invoices.view
POST/api/lis/invoicesCreate invoicelis.invoices.create
GET/api/lis/invoices/{id}Get invoice detailslis.invoices.view
PUT/api/lis/invoices/{id}Update invoicelis.invoices.update
DELETE/api/lis/invoices/{id}Delete invoicelis.invoices.delete
POST/api/lis/invoices/{id}/postPost invoicelis.invoices.update
POST/api/lis/invoices/{id}/cancelCancel invoicelis.invoices.update
POST/api/lis/invoices/generateGenerate invoice(s) from requestlis.insurance-invoices.generate

Query Parameters (List)

ParameterTypeDescription
searchstringSearch by invoice number
statusstringFilter by status
patient_idintegerFilter by patient
fromdateStart date filter
todateEnd date filter
invoice_typestringFilter by type (standard, patient_invoice, insurance_invoice)

Request / Response Examples

Create Invoice

bash
curl -X POST /api/lis/invoices \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "lab_request_id": 1,
    "patient_id": 1,
    "date": "2026-03-01",
    "insurance_contract_id": 1,
    "branch_id": 1,
    "items": [
      {"investigation_id": 1, "price": "5.000", "discount": "0.500", "tax": "0.000"},
      {"investigation_id": 5, "price": "3.000", "discount": "0.000", "tax": "0.000"}
    ]
  }'
dart
final response = await dio.post('/api/lis/invoices', data: {
  'lab_request_id': 1,
  'patient_id': 1,
  'date': '2026-03-01',
  'insurance_contract_id': 1,
  'branch_id': 1,
  'items': [
    {'investigation_id': 1, 'price': '5.000', 'discount': '0.500', 'tax': '0.000'},
    {'investigation_id': 5, 'price': '3.000', 'discount': '0.000', 'tax': '0.000'},
  ],
});

Post Invoice

bash
curl -X POST /api/lis/invoices/1/post \
  -H "Authorization: Bearer {token}"
dart
final response = await dio.post('/api/lis/invoices/1/post');

Cancel Invoice

bash
curl -X POST /api/lis/invoices/1/cancel \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"cancellation_reason": "Duplicate invoice"}'
dart
final response = await dio.post('/api/lis/invoices/1/cancel', data: {
  'cancellation_reason': 'Duplicate invoice',
});

Business Rules

  1. Post restrictions -- Only draft invoices can be posted. Posting creates a journal entry in the Accounting module.
  2. Cancel restrictions -- Only draft and posted invoices can be cancelled. Cancelling a posted invoice creates a reversal journal entry.
  3. Auto-totals -- Subtotal, discount, tax, and total are recalculated from line items.
  4. Insurance split -- If an insurance contract is applied, insurance_amount and patient_amount are calculated from contract terms.
  5. Balance due -- balance_due = total - amount_paid, updated on each payment.
  6. Delete restrictions -- Only draft invoices can be deleted. Posted invoices must be cancelled instead.
  7. Split invoicing -- For insured requests, POST /invoices/generate creates a patient_invoice + insurance_invoice pair. Standard requests get a single standard invoice. See Insurance Billing.
  8. Doctor commissions -- Commissions are only calculated for standard and patient_invoice types. Insurance invoices are skipped to avoid double-counting.
  9. Insurance accounting -- Insurance invoices use the contract's insurance_receivable_account_id and revenue_account_id for the journal entry instead of default accounts.

Moon ERP API Documentation