Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b0d8439
Add provider and location attributes in the BillableService
Muta-Jonathan Nov 13, 2025
d75bed9
Merge pull request #1 from Muta-Jonathan/(feat)Add-additional-attribu…
Muta-Jonathan Nov 14, 2025
e3f71f8
Merge pull request #2 from Muta-Jonathan/(feat)Add-is_default-Column-…
Muta-Jonathan Nov 17, 2025
ec37c18
(feat) Disable Bill auto creation on Drug Orders (#3)
Muta-Jonathan Dec 12, 2025
1852b2f
Merge remote-tracking branch upstream/main (#4)
Muta-Jonathan Dec 12, 2025
bc2e6eb
(feat) Disable Bill auto creation on Drug Orders (#5)
Muta-Jonathan Dec 12, 2025
5d150fc
Revert "(feat) Disable Bill auto creation on Drug Orders (#5)" (#6)
Muta-Jonathan Dec 15, 2025
095f0a3
Revert "Merge remote-tracking branch upstream/main (#4)" (#7)
Muta-Jonathan Dec 15, 2025
fb91a00
Add default value to disable auto drug order bill (#8)
Muta-Jonathan Dec 15, 2025
11f7fe1
Sync billing module with upstream fixes and features (excluding Java …
Muta-Jonathan Dec 17, 2025
3a32ae9
Fixing failing tests (#11)
Muta-Jonathan Dec 17, 2025
b82481c
add optional 'forceNewBill' flag to Bill REST API (#9)
Muta-Jonathan Dec 17, 2025
9256840
Add nested REST endpoints for managing bill line items (#12)
Muta-Jonathan Dec 18, 2025
e0178e6
Addition of Discount Attributes
jayg2002 Dec 24, 2025
af1ce88
Revert "Add nested REST endpoints for managing bill line items (#12)"
jayg2002 Dec 27, 2025
f39f9cd
Revert "Addition of Discount Attributes"
jayg2002 Dec 27, 2025
3aaedea
Revert "Add nested REST endpoints for managing bill line items (#12)"
jayg2002 Dec 27, 2025
b9dacee
Adding Discount attributes and removal od status checks
jayg2002 Dec 27, 2025
a0db564
Merge branch 'main' into add-Discount-attributes
jayg2002 Dec 29, 2025
e69bd07
Test fix
jayg2002 Dec 29, 2025
e42dd2e
Merge branch 'add-Discount-attributes' of https://github.com/indiemr/…
jayg2002 Dec 29, 2025
8043c71
Merge pull request #13 from indiemr/add-Discount-attributes
jayg2002 Dec 29, 2025
5303826
allow edit bill,payment using the BillUuid (#14)
Muta-Jonathan Jan 23, 2026
388e503
feat: add_gh_publisher
senthil-athiban Aug 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.openmrs.module.billing.api.model.CashierItemPrice;
import org.openmrs.module.billing.api.search.BillableServiceSearch;
import org.openmrs.module.billing.exemptions.BillingExemptions;
import org.openmrs.module.billing.util.Utils;
import org.openmrs.module.stockmanagement.api.StockManagementService;
import org.openmrs.module.stockmanagement.api.model.StockItem;
import org.springframework.aop.AfterReturningAdvice;
Expand All @@ -44,6 +43,8 @@

private static final Log LOG = LogFactory.getLog(GenerateBillFromOrderAdvice.class);

private static final String DISABLE_DRUG_ORDER_BILL_AUTO_CREATION = "billing.disableDrugOrderBillAutoCreation";

OrderService orderService = Context.getOrderService();

IBillService billService = Context.getService(IBillService.class);
Expand All @@ -58,7 +59,7 @@
* This is called immediately an order is saved
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

Check failure on line 62 in api/src/main/java/org/openmrs/module/billing/advice/GenerateBillFromOrderAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 32 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLDqey22SfKEvdXj&open=AZ_IgLDqey22SfKEvdXj&pullRequest=192
try {
ProgramWorkflowService workflowService = Context.getProgramWorkflowService();
if (method.getName().equals("saveOrder") && args.length > 0 && args[0] instanceof Order) {
Expand All @@ -75,6 +76,12 @@
String cashierUUID = Context.getAuthenticatedUser().getUuid();

if (order instanceof DrugOrder) {
// Check if drug order bill autocreation is disabled
boolean disableAutoBillCreation = Boolean.parseBoolean(
Context.getAdministrationService().getGlobalProperty(DISABLE_DRUG_ORDER_BILL_AUTO_CREATION));
if (disableAutoBillCreation) {
return; // Skip drug order bill processing
}
DrugOrder drugOrder = (DrugOrder) order;
Integer drugID = drugOrder.getDrug() != null ? drugOrder.getDrug().getDrugId() : 0;
double drugQuantity = drugOrder.getQuantity() != null ? drugOrder.getQuantity() : 0.0;
Expand Down Expand Up @@ -117,7 +124,7 @@
* @param config
* @return
*/
private boolean checkIfOrderIsExempted(ProgramWorkflowService workflowService, Order order,

Check failure on line 127 in api/src/main/java/org/openmrs/module/billing/advice/GenerateBillFromOrderAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 24 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLDqey22SfKEvdXk&open=AZ_IgLDqey22SfKEvdXk&pullRequest=192
Map<String, Set<Integer>> config) {
if (config == null || order == null || config.size() == 0) {
return false;
Expand All @@ -128,7 +135,7 @@
// check in programs list
List<String> programExemptions = config.keySet().stream().filter(key -> key.startsWith("program:"))
.collect(Collectors.toList());
if (programExemptions.size() > 0) {

Check warning on line 138 in api/src/main/java/org/openmrs/module/billing/advice/GenerateBillFromOrderAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use isEmpty() to check whether the collection is empty or not.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLDqey22SfKEvdXl&open=AZ_IgLDqey22SfKEvdXl&pullRequest=192
List<PatientProgram> programs = workflowService.getPatientPrograms(order.getPatient(), null, null, null,
new Date(), null, false);
Set<String> activeEnrollments = new HashSet<>();
Expand All @@ -144,7 +151,7 @@
//check if patient is active in the program
if (activeEnrollments.contains(programName)) {
// check if order is exempted
if (config.get(programEntry).contains(order.getConcept().getConceptId())) {

Check warning on line 154 in api/src/main/java/org/openmrs/module/billing/advice/GenerateBillFromOrderAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this if statement with the enclosing one.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLDqey22SfKEvdXi&open=AZ_IgLDqey22SfKEvdXi&pullRequest=192
return true;
}

Expand All @@ -154,7 +161,7 @@
}

// check age category
if (order.getPatient().getAge() < 5 && config.get("age<5") != null

Check warning on line 164 in api/src/main/java/org/openmrs/module/billing/advice/GenerateBillFromOrderAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this if-then-else statement by a single return statement.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLDqey22SfKEvdXm&open=AZ_IgLDqey22SfKEvdXm&pullRequest=192
&& config.get("age<5").contains(order.getConcept().getConceptId())) {
return true;
}
Expand Down Expand Up @@ -185,14 +192,14 @@
}

if (!itemPrices.isEmpty()) {
//List<CashierItemPrice> matchingPrices = itemPrices.stream().filter(p -> p.getPaymentMode().getUuid().equals(fetchPatientPayment(order))).collect(Collectors.toList());

Check warning on line 195 in api/src/main/java/org/openmrs/module/billing/advice/GenerateBillFromOrderAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This block of commented-out lines of code should be removed.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLDqey22SfKEvdXn&open=AZ_IgLDqey22SfKEvdXn&pullRequest=192
// billLineItem.setPrice(matchingPrices.isEmpty() ? itemPrices.get(0).getPrice() : matchingPrices.get(0).getPrice());
billLineItem.setPrice(itemPrices.get(0).getPrice());
} else {
if (stockitem != null && stockitem.getPurchasePrice() != null) {
billLineItem.setPrice(stockitem.getPurchasePrice());
} else {
billLineItem.setPrice(new BigDecimal(0.0));

Check warning on line 202 in api/src/main/java/org/openmrs/module/billing/advice/GenerateBillFromOrderAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use "BigDecimal.valueOf" instead.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLDqey22SfKEvdXo&open=AZ_IgLDqey22SfKEvdXo&pullRequest=192
}
}
billLineItem.setQuantity(quantity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.openmrs.module.billing.api.model.CashPoint;
import org.openmrs.module.billing.api.model.CashierItemPrice;
import org.openmrs.module.billing.api.search.BillableServiceSearch;
import org.openmrs.module.billing.util.Utils;
import org.openmrs.module.stockmanagement.api.StockManagementService;
import org.openmrs.module.stockmanagement.api.model.StockItem;
import org.springframework.aop.MethodBeforeAdvice;
Expand All @@ -53,6 +52,8 @@

private static final Log LOG = LogFactory.getLog(OrderCreationMethodBeforeAdvice.class);

private static final String DISABLE_DRUG_ORDER_BILL_AUTO_CREATION = "billing.disableDrugOrderBillAutoCreation";

OrderService orderService = Context.getOrderService();

IBillService billService = Context.getService(IBillService.class);
Expand All @@ -64,7 +65,7 @@
ICashPointService cashPointService = Context.getService(ICashPointService.class);

@Override
public void before(Method method, Object[] args, Object target) throws Throwable {

Check failure on line 68 in api/src/main/java/org/openmrs/module/billing/advice/OrderCreationMethodBeforeAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 31 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLFRey22SfKEvdXp&open=AZ_IgLFRey22SfKEvdXp&pullRequest=192
try {
// Extract the Order object from the arguments
if (method.getName().equals("saveOrder") && args.length > 0 && args[0] instanceof Order) {
Expand All @@ -79,6 +80,12 @@
Patient patient = order.getPatient();
String cashierUUID = Context.getAuthenticatedUser().getUuid();
if (order instanceof DrugOrder) {
// Check if drug order bill autocreation is disabled
boolean disableAutoBillCreation = Boolean.parseBoolean(
Context.getAdministrationService().getGlobalProperty(DISABLE_DRUG_ORDER_BILL_AUTO_CREATION));
if (disableAutoBillCreation) {
return; // Skip drug order bill processing
}
DrugOrder drugOrder = (DrugOrder) order;
Integer drugID = drugOrder.getDrug() != null ? drugOrder.getDrug().getDrugId() : 0;
double drugQuantity = drugOrder.getQuantity() != null ? drugOrder.getQuantity() : 0.0;
Expand Down Expand Up @@ -106,7 +113,7 @@
}
catch (Exception e) {
LOG.error(e);
e.printStackTrace();

Check warning on line 116 in api/src/main/java/org/openmrs/module/billing/advice/OrderCreationMethodBeforeAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure this debug feature is deactivated before delivering the code in production.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLFRey22SfKEvdXq&open=AZ_IgLFRey22SfKEvdXq&pullRequest=192
}
}

Expand Down Expand Up @@ -164,7 +171,7 @@
}
catch (Exception ex) {
LOG.error(ex);
ex.printStackTrace();

Check warning on line 174 in api/src/main/java/org/openmrs/module/billing/advice/OrderCreationMethodBeforeAdvice.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure this debug feature is deactivated before delivering the code in production.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-billing&issues=AZ_IgLFRey22SfKEvdXr&open=AZ_IgLFRey22SfKEvdXr&pullRequest=192
}
}

Expand Down
11 changes: 11 additions & 0 deletions api/src/main/java/org/openmrs/module/billing/api/IBillService.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@ public interface IBillService extends IEntityDataService<Bill> {
@Authorized(PrivilegeConstants.VIEW_BILLS)
Bill getByUuid(String uuid);

/**
* Gets a bill by UUID, optionally including voided line items.
*
* @param uuid The bill UUID.
* @param includeVoidedLineItems {@code true} to include voided line items, {@code false} to exclude
* them.
* @return The bill with the specified UUID.
*/
@Authorized({ PrivilegeConstants.VIEW_BILLS })
Bill getByUuid(String uuid, boolean includeVoidedLineItems);

/**
* Gets bill receipt using the specified {@link Bill} settings.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@

import java.util.List;

import org.openmrs.module.billing.api.base.entity.IEntityDataService;
import org.openmrs.module.billing.api.base.entity.IMetadataDataService;
import org.openmrs.module.billing.api.model.BillableService;
import org.openmrs.module.billing.api.search.BillableServiceSearch;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public interface IBillableItemsService extends IEntityDataService<BillableService> {
public interface IBillableItemsService extends IMetadataDataService<BillableService> {

List<BillableService> findServices(final BillableServiceSearch search);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
*/
package org.openmrs.module.billing.api;

import org.openmrs.module.billing.api.base.entity.IEntityDataService;
import org.openmrs.module.billing.api.base.entity.IMetadataDataService;
import org.openmrs.module.billing.api.model.CashierItemPrice;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public interface ICashierItemPriceService extends IEntityDataService<CashierItemPrice> {}
public interface ICashierItemPriceService extends IMetadataDataService<CashierItemPrice> {}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@

import java.util.List;

import org.openmrs.module.billing.api.base.entity.IEntityDataService;
import org.openmrs.module.billing.api.base.entity.IMetadataDataService;
import org.openmrs.module.billing.api.model.BillableService;
import org.openmrs.module.billing.api.model.CashierItemPrice;
import org.openmrs.module.stockmanagement.api.model.StockItem;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public interface ItemPriceService extends IEntityDataService<CashierItemPrice> {
public interface ItemPriceService extends IMetadataDataService<CashierItemPrice> {

CashierItemPrice save(CashierItemPrice price);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
*/
package org.openmrs.module.billing.api.impl;

import org.openmrs.api.context.Context;
import org.openmrs.module.billing.api.BillLineItemService;
import org.openmrs.module.billing.api.IBillService;
import org.openmrs.module.billing.api.base.entity.impl.BaseEntityDataServiceImpl;
import org.openmrs.module.billing.api.base.entity.security.IEntityAuthorizationPrivileges;
import org.openmrs.module.billing.api.model.Bill;
import org.openmrs.module.billing.api.model.BillLineItem;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -29,7 +32,7 @@ protected IEntityAuthorizationPrivileges getPrivileges() {

@Override
protected void validate(BillLineItem object) {

// Status checks removed to allow bill modification regardless of status
}

@Override
Expand All @@ -51,4 +54,47 @@ public String getPurgePrivilege() {
public String getGetPrivilege() {
return null;
}

@Override
public BillLineItem voidEntity(BillLineItem entity, String reason) {
BillLineItem voidedLineItem = super.voidEntity(entity, reason);

if (voidedLineItem != null && voidedLineItem.getBill() != null) {
Bill bill = voidedLineItem.getBill();
bill.synchronizeBillStatus();
}

return voidedLineItem;
}

@Override
public BillLineItem unvoidEntity(BillLineItem entity) {
BillLineItem unvoidedLineItem = super.unvoidEntity(entity);

if (unvoidedLineItem != null && unvoidedLineItem.getBill() != null) {
Bill bill = unvoidedLineItem.getBill();
bill.synchronizeBillStatus();
}

return unvoidedLineItem;
}

@Override
public void purge(BillLineItem entity) {
Bill bill = null;
if (entity != null && entity.getBill() != null) {
bill = entity.getBill();
}

super.purge(entity);

if (bill != null) {
// Remove the line item from the bill's collection
bill.removeLineItem(entity);
bill.synchronizeBillStatus();
// Save the bill to persist the collection change
IBillService billService = Context.getService(IBillService.class);
billService.save(bill);
}
}
}
Loading