diff --git a/api/src/main/java/org/openmrs/module/billing/api/db/hibernate/ImmutableBillInterceptor.java b/api/src/main/java/org/openmrs/module/billing/api/db/hibernate/ImmutableBillInterceptor.java index 8360cbff..ead9950d 100644 --- a/api/src/main/java/org/openmrs/module/billing/api/db/hibernate/ImmutableBillInterceptor.java +++ b/api/src/main/java/org/openmrs/module/billing/api/db/hibernate/ImmutableBillInterceptor.java @@ -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() { diff --git a/api/src/main/java/org/openmrs/module/billing/api/model/Bill.java b/api/src/main/java/org/openmrs/module/billing/api/model/Bill.java index bf65b11b..81785af2 100644 --- a/api/src/main/java/org/openmrs/module/billing/api/model/Bill.java +++ b/api/src/main/java/org/openmrs/module/billing/api/model/Bill.java @@ -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; @@ -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; @@ -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; @@ -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) { diff --git a/api/src/main/java/org/openmrs/module/billing/api/model/BillStatus.java b/api/src/main/java/org/openmrs/module/billing/api/model/BillStatus.java index 29e17d2e..a8215321 100644 --- a/api/src/main/java/org/openmrs/module/billing/api/model/BillStatus.java +++ b/api/src/main/java/org/openmrs/module/billing/api/model/BillStatus.java @@ -23,7 +23,9 @@ public enum BillStatus { PAID(), CANCELLED(), ADJUSTED(), - EXEMPTED(); + EXEMPTED(), + REFUND_REQUESTED(), + REFUNDED(); BillStatus() { } diff --git a/api/src/main/resources/Bill.hbm.xml b/api/src/main/resources/Bill.hbm.xml index dd88092c..de03d6a0 100644 --- a/api/src/main/resources/Bill.hbm.xml +++ b/api/src/main/resources/Bill.hbm.xml @@ -139,6 +139,12 @@ + + + + + diff --git a/api/src/test/java/org/openmrs/module/billing/api/model/BillTest.java b/api/src/test/java/org/openmrs/module/billing/api/model/BillTest.java index 17a1240a..06e53428 100644 --- a/api/src/test/java/org/openmrs/module/billing/api/model/BillTest.java +++ b/api/src/test/java/org/openmrs/module/billing/api/model/BillTest.java @@ -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(); diff --git a/omod/src/main/java/org/openmrs/module/billing/web/rest/resource/BillResource.java b/omod/src/main/java/org/openmrs/module/billing/web/rest/resource/BillResource.java index df393725..c1e2ff3f 100644 --- a/omod/src/main/java/org/openmrs/module/billing/web/rest/resource/BillResource.java +++ b/omod/src/main/java/org/openmrs/module/billing/web/rest/resource/BillResource.java @@ -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; @@ -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; @@ -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; } @@ -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); diff --git a/omod/src/main/resources/liquibase.xml b/omod/src/main/resources/liquibase.xml index 118d17c3..582840d0 100644 --- a/omod/src/main/resources/liquibase.xml +++ b/omod/src/main/resources/liquibase.xml @@ -1095,4 +1095,34 @@ baseTableName="bill_exemption_rule" baseColumnNames="voided_by" referencedTableName="users" referencedColumnNames="user_id"/> + + + Widen status columns for REFUND_REQUESTED and add refund audit fields to cashier_bill + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file