Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -29,7 +29,8 @@ public class ImmutableBillInterceptor extends ImmutableEntityInterceptor {

private static final String[] MUTABLE_PROPERTY_NAMES = new String[] { "changedBy", "dateChanged", "voided", "dateVoided",
"voidedBy", "voidReason", "payment", "billAdjusted", "adjustmentReason", "adjustedBy", "receiptPrinted",
"status", "receiptNumber" };
"status", "receiptNumber", "refundReason", "refundRequestedBy", "dateRefundRequested", "refundApprovedBy",
"dateRefundApproved" };

@Override
protected Class<?> getSupportedType() {
Expand Down
15 changes: 15 additions & 0 deletions api/src/main/java/org/openmrs/module/billing/api/model/Bill.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.math.BigDecimal;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand All @@ -25,6 +26,7 @@
import org.openmrs.BaseOpenmrsData;
import org.openmrs.Patient;
import org.openmrs.Provider;
import org.openmrs.User;
import org.openmrs.api.context.Context;
import org.openmrs.module.billing.api.util.PrivilegeConstants;
import org.openmrs.module.stockmanagement.api.model.StockItem;
Expand Down Expand Up @@ -63,6 +65,16 @@ public class Bill extends BaseOpenmrsData {

private String adjustmentReason;

private String refundReason;

private User refundRequestedBy;

private Date dateRefundRequested;

private User refundApprovedBy;

private Date dateRefundApproved;

public BigDecimal getTotal() {
BigDecimal total = BigDecimal.ZERO;

Expand Down Expand Up @@ -169,6 +181,9 @@ public void addPayment(Payment payment) {
}

public void synchronizeBillStatus() {
if (this.status == BillStatus.REFUND_REQUESTED || this.status == BillStatus.REFUNDED) {
return;
}
if (!this.getPayments().isEmpty() && getTotalPayments().compareTo(BigDecimal.ZERO) > 0) {
boolean billFullySettled = getTotalPayments().compareTo(getTotal()) >= 0;
if (billFullySettled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public enum BillStatus {
PAID(),
CANCELLED(),
ADJUSTED(),
EXEMPTED();
EXEMPTED(),
REFUND_REQUESTED(),
REFUNDED();

BillStatus() {
}
Expand Down
6 changes: 6 additions & 0 deletions api/src/main/resources/Bill.hbm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@
<property name="uuid" type="java.lang.String" column="uuid" length="38" unique="true"/>
<property name="adjustmentReason" type="java.lang.String" column="adjustment_reason" length="500"
not-null="false"/>
<property name="refundReason" type="java.lang.String" column="refund_reason" length="500"
not-null="false"/>
<many-to-one name="refundRequestedBy" class="org.openmrs.User" column="refund_requested_by"/>
<property name="dateRefundRequested" type="java.util.Date" column="date_refund_requested" length="19"/>
<many-to-one name="refundApprovedBy" class="org.openmrs.User" column="refund_approved_by"/>
<property name="dateRefundApproved" type="java.util.Date" column="date_refund_approved" length="19"/>
</class>

<class name="org.openmrs.module.billing.api.model.BillLineItem" table="cashier_bill_line_item">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,52 @@ public void synchronizeBillStatus_shouldUpdateAllNonVoidedLineItemsToPaidWhenBil
assertNull(voidedLineItem.getPaymentStatus());
}

@Test
public void synchronizeBillStatus_shouldNotOverwriteRefundRequestedStatus() {
Bill bill = new Bill();
bill.setLineItems(new ArrayList<>());
bill.setPayments(new HashSet<>());
bill.setStatus(BillStatus.REFUND_REQUESTED);

BillLineItem lineItem = new BillLineItem();
lineItem.setPrice(BigDecimal.valueOf(100));
lineItem.setQuantity(1);
lineItem.setVoided(false);
bill.getLineItems().add(lineItem);

Payment payment = new Payment();
payment.setAmountTendered(BigDecimal.valueOf(100));
payment.setVoided(false);
bill.getPayments().add(payment);

bill.synchronizeBillStatus();

assertEquals(BillStatus.REFUND_REQUESTED, bill.getStatus());
}

@Test
public void synchronizeBillStatus_shouldNotOverwriteRefundedStatus() {
Bill bill = new Bill();
bill.setLineItems(new ArrayList<>());
bill.setPayments(new HashSet<>());
bill.setStatus(BillStatus.REFUNDED);

BillLineItem lineItem = new BillLineItem();
lineItem.setPrice(BigDecimal.valueOf(100));
lineItem.setQuantity(1);
lineItem.setVoided(false);
bill.getLineItems().add(lineItem);

Payment payment = new Payment();
payment.setAmountTendered(BigDecimal.valueOf(100));
payment.setVoided(false);
bill.getPayments().add(payment);

bill.synchronizeBillStatus();

assertEquals(BillStatus.REFUNDED, bill.getStatus());
}

@Test
public void setLineItems_shouldAllowSettingLineItemsOnNewBill() {
Bill bill = new Bill();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
*/
package org.openmrs.module.billing.web.rest.resource;

import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
Expand All @@ -35,6 +37,7 @@
import org.openmrs.module.billing.api.model.BillLineItem;
import org.openmrs.module.billing.api.model.BillStatus;
import org.openmrs.module.billing.api.model.CashPoint;
import org.openmrs.module.billing.api.util.PrivilegeConstants;
import org.openmrs.module.billing.api.model.Payment;
import org.openmrs.module.billing.api.model.Timesheet;
import org.openmrs.module.billing.api.search.BillSearch;
Expand Down Expand Up @@ -77,6 +80,11 @@ public DelegatingResourceDescription getRepresentationDescription(Representation
description.addProperty("receiptNumber");
description.addProperty("status");
description.addProperty("adjustmentReason");
description.addProperty("refundReason");
description.addProperty("refundRequestedBy", Representation.REF);
description.addProperty("dateRefundRequested");
description.addProperty("refundApprovedBy", Representation.REF);
description.addProperty("dateRefundApproved");
description.addProperty("uuid");
return description;
}
Expand Down Expand Up @@ -122,6 +130,22 @@ public void setBillStatus(Bill instance, BillStatus status) {
instance.setStatus(status);
} else if (instance.getStatus() == BillStatus.PENDING && status == BillStatus.POSTED) {
instance.setStatus(status);
} else if (instance.getStatus() == BillStatus.PAID && status == BillStatus.REFUND_REQUESTED) {
instance.setRefundRequestedBy(Context.getAuthenticatedUser());
instance.setDateRefundRequested(new Date());
instance.setStatus(status);
} else if (instance.getStatus() == BillStatus.REFUND_REQUESTED && status == BillStatus.REFUNDED) {
if (!Context.hasPrivilege(PrivilegeConstants.REFUND_MONEY)) {
throw new AccessControlException("Access denied to issue refund.");
}
instance.setRefundApprovedBy(Context.getAuthenticatedUser());
instance.setDateRefundApproved(new Date());
instance.setStatus(status);
} else if (instance.getStatus() == BillStatus.REFUND_REQUESTED && status == BillStatus.PAID) {
if (!Context.hasPrivilege(PrivilegeConstants.REFUND_MONEY)) {
throw new AccessControlException("Access denied to reject refund request.");
}
instance.setStatus(status);
}
if (status == BillStatus.POSTED) {
RoundingUtil.handleRoundingLineItem(instance);
Expand Down
30 changes: 30 additions & 0 deletions omod/src/main/resources/liquibase.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1095,4 +1095,34 @@
baseTableName="bill_exemption_rule" baseColumnNames="voided_by"
referencedTableName="users" referencedColumnNames="user_id"/>
</changeSet>

<changeSet id="openmrs.billing-004-20260210-refund-support" author="UjjawalPrabhat">
<comment>Widen status columns for REFUND_REQUESTED and add refund audit fields to cashier_bill</comment>

<modifyDataType tableName="cashier_bill" columnName="status" newDataType="varchar(50)"/>
<modifyDataType tableName="cashier_bill_line_item" columnName="payment_status" newDataType="varchar(50)"/>

<addColumn tableName="cashier_bill">
<column name="refund_reason" type="varchar(500)"><constraints nullable="true"/></column>
</addColumn>
<addColumn tableName="cashier_bill">
<column name="refund_requested_by" type="int"><constraints nullable="true"/></column>
</addColumn>
<addColumn tableName="cashier_bill">
<column name="date_refund_requested" type="datetime"><constraints nullable="true"/></column>
</addColumn>
<addColumn tableName="cashier_bill">
<column name="refund_approved_by" type="int"><constraints nullable="true"/></column>
</addColumn>
<addColumn tableName="cashier_bill">
<column name="date_refund_approved" type="datetime"><constraints nullable="true"/></column>
</addColumn>

<addForeignKeyConstraint constraintName="cashier_bill_refund_requested_by_fk"
baseTableName="cashier_bill" baseColumnNames="refund_requested_by"
referencedTableName="users" referencedColumnNames="user_id"/>
<addForeignKeyConstraint constraintName="cashier_bill_refund_approved_by_fk"
baseTableName="cashier_bill" baseColumnNames="refund_approved_by"
referencedTableName="users" referencedColumnNames="user_id"/>
</changeSet>
</databaseChangeLog>