Hi all,
I’m starting this thread to explain the billing changes recently implemented, why they were required, and to get feedback on a particular behaviour in the billing flow.
Why this change was required
A validation was added earlier to prevent modifications once a bill becomes POSTED.
However, this resulted in a major side effect:
Users could no longer make payments on POSTED bills, even though payments do not alter bill line items.
On investigation, the root issue was not the rule itself, but where the validation logic was placed.
Compact Summary of the Implemented Solution
Primary Goal:
Ensure that bill line items can only be modified when a bill is PENDING, while still allowing valid actions like payments on POSTED bills.
Key Implementation Updates
| Area | What Was Done | Why |
|---|---|---|
| BillLineItem.equals() / hashCode() | Implemented business-based equality using UUID, quantity, price, item UUID, billable service UUID, voided flag | Detect duplicates and identify real changes to line items |
| BillResource.setBillLineItems() | Validation now checks both bill status and whether line items actually changed | Prevents blocking legitimate payments while still enforcing immutability of line items on non-PENDING bills |
Business Rules Enforced
Line items editable only when bill is PENDING/new
Duplicate line items prevented when merging pending bills
Payments allowed even on POSTED bills if line items are unchanged
REST layer ensures immutability once status moves past PENDING
Key Technical Findings
Unexpected mutation before setBillLineItems() runs
While debugging, I found that before the setBillLineItems() method in BillResource is invoked, the Bill instance already contains modified line items.
Cause:
- ConversionUtil.convertMap() mutates the line item collection directly on the existing Bill instance instead of preparing a detached copy.
This means by the time setBillLineItems() executes, both the original and the incoming line items appear identical, making comparison unreliable.
Workaround Implemented
To correctly validate changes:
- I had to evict the current bill instance from the Hibernate session,
- Reload the original bill from the database, and
- Compare line items against this clean version before allowing or rejecting modifications.
This ensures we detect real user-initiated changes despite Hibernate and ConversionUtil mutating collections earlier in the flow.
Question for the community
Is there a better design approach for handling this validation, given the following constraints?
- Hibernate mutates entity collections before resource setters are called
- ConversionUtil writes directly into domain objects
- We need a reliable pre-mutation comparison of line items to enforce the “immutability after POSTED” rule
Any architectural guidance or examples from other OpenMRS modules that handle similar REST + Hibernate flows would be greatly appreciated.
Some Pictures that might help paint some picture:
Location domain object ref is being taken:






