Product EngineeringFeaturesOrder SplitBackend

Data Model

Financial recalculation logic, table-level action matrix, and dependent entity handling for Order Split.

๐Ÿ‘ค Sachin Sharma, Nilesh Bhusari๐Ÿ“… Updated: May 2, 2026๐Ÿท๏ธ feature๐Ÿท๏ธ backend๐Ÿท๏ธ database๐Ÿท๏ธ billing

Strategy

Order Split uses a shift FK + selective clone model โ€” rows either travel with the moved tests or get copied independently onto the new bill.


Financial recalculation

All financial fields on the split bill are derived proportionally from the parent bill.

Proportion formula

split_base_amount   = ฮฃ (testAmount - testConsc)  for each non-profile BillingInfo in selection
original_base_total = parent.billTotalAmount - parent.billAdditionalAmount
                      + parent.TDSAmount - parent.vat

split_proportion = split_base_amount / original_base_total

Derived split values

FieldFormula
vatoriginal_vat ร— split_proportion
TDSAmountoriginal_tds ร— split_proportion
billAdditionalAmountoriginal_additional ร— split_proportion
billTotalAmountsplit_base_amount + split_additional - split_tds + split_vat
vat_percent(split_vat / (split_total - split_vat)) ร— 100
co_pay_amountฮฃ co_pay_amount per selected non-profile row
deductible_amountฮฃ deductible_amount per selected non-profile row
patientPayableAmountco_pay_amount + deductible_amount

Parent bill values are reduced by exactly the split-side values (no rounding loss across both bills).

Non-insurance destination source

When new_source is not insurance, the split bill has insurance-specific fields reset to 0:

  • co_pay_amount = 0
  • deductible_amount = 0
  • patientPayableAmount = 0

The same reset is applied to the moved BillingInfo rows via shift_update_billing_info.

Order number

The split bill's orderNumber is derived from the parent:

parent.orderNumber = "ORD-1234"     โ†’  split.orderNumber = "ORD-1234~1"
parent.orderNumber = "ORD-1234~1"  โ†’  split.orderNumber = "ORD-1234~2"

Table action matrix

Model / TableActionNotes
billingCreate + update parentSplit bill created; parent bill reduced
billingInfoShift FKSelected rows moved to split bill
labReportRelationShift FKMoved test report rows updated to split bill
collectedSampleConditional create + relinkNew sample only when parent and split share one
billing_icdShift + createTest-level rows shifted; bill-level rows copied
billing_modifierShift + createTest-level rows shifted; bill-level rows copied
org_test_count_ledgerShift FKRows for moved tests reassigned to split bill
paymentsCreateZero-amount CASH row bootstraps split bill
symptoms_user_bill_relationCreateParent rows cloned for split bill
UserBillInsuranceCreateSplit bill gets insurance row when source is insurance
organizationTransactionFusion webhookNegative-amount ledger entry sent via Fusion; note_entry is true for PREPAID orgs only. Skipped when manageLedger is disabled.
bill_approval_actionCreateParent approval row cloned to split bill
lab_missing_detailsCreateUnresolved bill-level rows copied to split bill
attachmentsCopy + soft-deleteSmart reports soft-deleted on parent; eligible attachments copied
QuestionValue (AOE)Shift + createBill-level AOE cloned; test/profile-level AOE shifted for moved reports
QuestionValue (consent)Shift + createResponses for moved reports shifted; bill/patient-level responses cloned
LabFormLinkedProcessesShift + createPatient/bill-level processes cloned; test/profile-level processes shifted
reportValues / LRR doc storesNo changePreserved via LRR identity continuity
ReflexTestDetailsNo changeLogging table
NotificationNo changeLogging table
SmartReportGenerationNo changeLogging table
invoiceNo changeInvoiced bills are blocked from split
formFNo impactStays on parent bill
billTransactionNo impactSplit bill starts with a clean payment history
onlinePaymentNo impactDeferred table; currently not in use
LinkedBillsNo impactABDM-linked bills are blocked before reaching this point
inventoryTransactionNo impactConsumption logged at parent billing stage
DoctorReportRelationNo impactRecords are linked to reports
LabFormCreate (clone) / UnhandledConsent forms are cloned for the split bill (revoked forms excluded); AOE config form structures are not migrated (only their QuestionValue responses are moved)
BillClassifierTagsUnhandledPresence blocks split; not migrated
TestClinicalInfoUnhandledPresence blocks split; not migrated
ProcessedFileUnhandledPresence blocks split; not migrated
homeCollectionUnhandledPresence blocks split
emrAppointmentsUnhandledPresence blocks split
InsuranceClaimUnhandledPresence blocks split
BillClaimRelationUnhandledPresence blocks split
KitUnhandledPresence blocks split
ShippingDetailsUnhandledPresence blocks split
privilegeCardLedgerUnhandledNot migrated; no guard
prescriptionsUnhandledNot migrated; no guard

Dependent entity details

Sample handling

A new CollectedSample is created only when a sample is shared โ€” i.e. some tests staying on the parent and some moving to the split bill use the same sample row. If all tests on a sample move together, the existing sample row is simply relinked.

New samples reset positional fields: rackNo = 0, xPos = 0, yPos = 0, location = "". A new autoSampleID is generated.

Attachment handling

  1. Active attachments are fetched for both the bill and moved report IDs.
  2. Smart report attachments are soft-deleted on the parent (is_deleted = True).
  3. Remaining allowed attachments are copied: Storage Manager is tried first; S3 direct copy with manual ES indexing is the fallback.
  4. Copied attachments get new filenames ({original_name}_{timestamp}.{ext}).
  5. The split bill's billingAttachment field is updated to the last copied URL.

ICD and modifier handling

  • Bill-level rows (no bill_info_id): new rows are created pointing to the split bill.
  • Test-level rows (have bill_info_id): rows for moved BillingInfo IDs are shifted via FK update.

LabForm records are split by type:

  • Consent LabForm โ€” IS migrated. A new LabForm record is cloned for the split bill (new lab_form_slug UUID). Only non-revoked forms are processed.
  • AOE config LabForm โ€” NOT migrated. The form config stays on the parent. Only the QuestionValue responses are moved.

QuestionValue records for moved reports are shifted; bill/patient-level records are cloned. AOE Promotion and Store process types are left on the parent bill.


See Transactions and Sync for the full migration sequence.

On this page