/* * The contents of this file are subject to the OpenMRS Public License * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and * limitations under the License. * * Copyright (C) OpenHMIS. All Rights Reserved. */ package org.openmrs.module.openhmis.cashier.api.model; import java.math.BigDecimal; import java.security.AccessControlException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.openmrs.BaseOpenmrsData; import org.openmrs.Patient; import org.openmrs.Provider; import org.openmrs.api.context.Context; import org.openmrs.module.openhmis.cashier.api.util.PrivilegeConstants; import org.openmrs.module.openhmis.inventory.api.model.Item; import org.openmrs.module.openhmis.inventory.api.model.ItemPrice; /** * Model class that represents a list of {@link BillLineItem}s and {@link Payment}s created by a cashier for a patient. */ public class Bill extends BaseOpenmrsData { public static final long serialVersionUID = 0L; private Integer billId; private String receiptNumber; private Provider cashier; private Patient patient; private CashPoint cashPoint; private Bill billAdjusted; private BillStatus status; private List<BillLineItem> lineItems; private Set<Payment> payments; private Set<Bill> adjustedBy; private Boolean receiptPrinted = false; private String adjustmentReason; public String getAdjustmentReason() { return adjustmentReason; } public void setAdjustmentReason(String adjustmentReason) { this.adjustmentReason = adjustmentReason; } public Boolean isReceiptPrinted() { return receiptPrinted; } public void setReceiptPrinted(Boolean receiptPrinted) { this.receiptPrinted = receiptPrinted; } public BigDecimal getTotal() { BigDecimal total = BigDecimal.ZERO; if (lineItems != null) { for (BillLineItem line : lineItems) { if (line != null && !line.getVoided()) { total = total.add(line.getTotal()); } } } return total; } public BigDecimal getTotalPayments() { BigDecimal total = BigDecimal.ZERO; if (payments != null) { for (Payment payment : payments) { if (payment != null && !payment.getVoided()) { total = total.add(payment.getAmount()); } } } return total; } public BigDecimal getAmountPaid() { BigDecimal total = getTotal(); BigDecimal totalPayments = getTotalPayments(); return total.min(totalPayments); } @Override public Integer getId() { return billId; } @Override public void setId(Integer id) { billId = id; } public String getReceiptNumber() { return receiptNumber; } public void setReceiptNumber(String number) { this.receiptNumber = number; } public Provider getCashier() { return cashier; } public void setCashier(Provider cashier) { this.cashier = cashier; } public Patient getPatient() { return patient; } public void setPatient(Patient patient) { this.patient = patient; } public CashPoint getCashPoint() { return cashPoint; } public void setCashPoint(CashPoint cashPoint) { this.cashPoint = cashPoint; } public Bill getBillAdjusted() { return billAdjusted; } public void setBillAdjusted(Bill billAdjusted) { this.billAdjusted = billAdjusted; if (billAdjusted != null) { billAdjusted.setStatus(BillStatus.ADJUSTED); } } public BillStatus getStatus() { return status; } public void setStatus(BillStatus status) { this.status = status; } public List<BillLineItem> getLineItems() { return lineItems; } public void setLineItems(List<BillLineItem> lineItems) { this.lineItems = lineItems; } public BillLineItem addLineItem(Item item, ItemPrice price, int quantity) { if (item == null) { throw new NullPointerException("The item to add must be defined."); } if (price == null) { throw new NullPointerException("The item price must be defined."); } return addLineItem(item, price.getPrice(), price.getName(), quantity); } public BillLineItem addLineItem(Item item, BigDecimal price, String priceName, int quantity) { if (item == null) { throw new IllegalArgumentException("The item to add must be defined."); } if (price == null) { throw new IllegalArgumentException("The item price must be defined."); } BillLineItem lineItem = new BillLineItem(); lineItem.setBill(this); lineItem.setItem(item); lineItem.setPrice(price); lineItem.setPriceName(priceName); lineItem.setQuantity(quantity); addLineItem(lineItem); return lineItem; } public void addLineItem(BillLineItem item) { if (item == null) { throw new NullPointerException("The list item to add must be defined."); } if (this.lineItems == null) { this.lineItems = new ArrayList<BillLineItem>(); } this.lineItems.add(item); item.setBill(this); } public void removeLineItem(BillLineItem item) { if (item != null) { if (this.lineItems != null) { this.lineItems.remove(item); } } } public Set<Payment> getPayments() { return payments; } public void setPayments(Set<Payment> payments) { this.payments = payments; } public Payment addPayment(PaymentMode mode, Set<PaymentAttribute> attributes, BigDecimal amount, BigDecimal amountTendered) { if (mode == null) { throw new NullPointerException("The payment mode must be defined."); } if (amount == null) { throw new NullPointerException(("The payment amount must be defined.")); } Payment payment = new Payment(); payment.setInstanceType(mode); payment.setAmount(amount); payment.setAmountTendered(amountTendered); if (attributes != null && attributes.size() > 0) { payment.setAttributes(attributes); for (PaymentAttribute attribute : attributes) { attribute.setOwner(payment); } } addPayment(payment); return payment; } public void addPayment(Payment payment) { if (payment == null) { throw new NullPointerException("The payment to add must be defined."); } if (this.payments == null) { this.payments = new HashSet<Payment>(); } this.payments.add(payment); payment.setBill(this); this.checkPaidAndUpdateStatus(); } public boolean checkPaidAndUpdateStatus() { if (this.getPayments().size() > 0) { if (this.status == BillStatus.PENDING || this.status == BillStatus.POSTED) { if (getTotalPayments().compareTo(getTotal()) >= 0) { this.setStatus(BillStatus.PAID); return true; } else if (this.status == BillStatus.PENDING) { this.status = BillStatus.POSTED; } } } return false; } public void removePayment(Payment payment) { if (payment != null && this.payments != null) { this.payments.remove(payment); } } public Set<Bill> getAdjustedBy() { return adjustedBy; } public void setAdjustedBy(Set<Bill> adjustedBy) { this.adjustedBy = adjustedBy; } public void addAdjustedBy(Bill adjustedBill) { checkAuthorizedToAdjust(); if (adjustedBill == null) { throw new NullPointerException("The adjusted bill to add must be defined."); } if (this.adjustedBy == null) { this.adjustedBy = new HashSet<Bill>(); } adjustedBill.setBillAdjusted(this); this.adjustedBy.add(adjustedBill); } public void removeAdjustedBy(Bill adjustedBill) { if (adjustedBill != null && this.adjustedBy != null) { this.adjustedBy.remove(adjustedBill); } } private void checkAuthorizedToAdjust() { if (!Context.hasPrivilege(PrivilegeConstants.ADJUST_BILLS)) { throw new AccessControlException("Access denied to adjust bill."); } } public void recalculateLineItemOrder() { int orderCounter = 0; for (BillLineItem lineItem : this.getLineItems()) { lineItem.setLineItemOrder(orderCounter++); } } public String getLastUpdated() { SimpleDateFormat ft = Context.getDateTimeFormat(); String changedStr = (this.getDateChanged() != null) ? ft.format(this.getDateChanged()) : null; String createdStr = (this.getDateCreated() != null) ? ft.format(this.getDateCreated()) : ""; String dateString = (changedStr != null) ? changedStr : createdStr; return dateString; } }