/* * 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.util; import java.math.BigDecimal; import java.math.BigInteger; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openmrs.api.context.Context; import org.openmrs.module.openhmis.cashier.ModuleSettings; import org.openmrs.module.openhmis.cashier.api.ICashierOptionsService; import org.openmrs.module.openhmis.cashier.api.ICashierOptionsServiceTest; import org.openmrs.module.openhmis.cashier.api.model.Bill; import org.openmrs.module.openhmis.cashier.api.model.BillLineItem; import org.openmrs.module.openhmis.cashier.api.model.CashierOptions; import org.openmrs.module.openhmis.cashier.api.model.CashierSettings; import org.openmrs.module.openhmis.inventory.api.IItemDataService; import org.openmrs.module.openhmis.inventory.api.IItemDataServiceTest; import org.openmrs.module.openhmis.inventory.api.model.Item; import org.openmrs.test.BaseModuleContextSensitiveTest; public class RoundingUtilTest extends BaseModuleContextSensitiveTest { private ICashierOptionsService cashOptService; @Before public void before() throws Exception { cashOptService = Context.getService(ICashierOptionsService.class); executeDataSet(ICashierOptionsServiceTest.OPTIONS_DATASET_VALID); executeDataSet(IItemDataServiceTest.ITEM_DATASET); } /** * Assumes that the roundToNearest option is 5 * @see RoundingUtil#handleRoundingLineItem(Bill) * @verifies add a rounding line item with the appropriate value */ @Test public void addRoundingLineItem_shouldAddARoundingLineItemWithTheAppropriateValue() throws Exception { CashierOptions cashierOptions = cashOptService.getOptions(); Assert.assertEquals(5, (int)cashierOptions.getRoundToNearest()); // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(3)); item.setQuantity(1); bill.addLineItem(item); // One line item Assert.assertEquals(1, bill.getLineItems().size()); // Do rounding RoundingUtil.handleRoundingLineItem(bill); // Now two line items Assert.assertEquals(2, bill.getLineItems().size()); // Assert rounding item's price BillLineItem rounding = bill.getLineItems().get(1); Assert.assertEquals(new BigDecimal(2), rounding.getTotal()); // Assert evenly divisible by nearest Assert.assertEquals(new BigDecimal(0), bill.getTotal().remainder( new BigDecimal(cashierOptions.getRoundToNearest()))); } /** * @verifies round bills with a non zero amount correctly for MID * @see RoundingUtil#handleRoundingLineItem(Bill) */ @Test public void handleRoundingLineItem_shouldRoundBillsWithANonZeroAmountCorrectlyForMID() throws Exception { CashierOptions cashierOptions = cashOptService.getOptions(); Assert.assertEquals(5, (int)cashierOptions.getRoundToNearest()); Assert.assertEquals(CashierOptions.RoundingMode.MID, cashierOptions.getRoundingMode()); // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(3.5)); item.setQuantity(1); bill.addLineItem(item); // One line item Assert.assertEquals(1, bill.getLineItems().size()); // Do rounding RoundingUtil.handleRoundingLineItem(bill); // Now two line items Assert.assertEquals(2, bill.getLineItems().size()); // Assert rounding item's price BillLineItem rounding = bill.getLineItems().get(1); Assert.assertEquals(new BigDecimal(1.5), rounding.getTotal()); } /** * @verifies round bills with a non zero amount correctly for CEILING * @see RoundingUtil#handleRoundingLineItem(Bill) */ @Test public void handleRoundingLineItem_shouldRoundBillsWithANonZeroAmountCorrectlyForCEILING() throws Exception { CashierSettings settings = ModuleSettings.loadSettings(); settings.setCashierRoundingMode(CashierOptions.RoundingMode.CEILING.toString()); ModuleSettings.saveSettings(settings); settings = ModuleSettings.loadSettings(); Assert.assertEquals(5, (int)settings.getCashierRoundingToNearest()); Assert.assertEquals(CashierOptions.RoundingMode.CEILING.toString(), settings.getCashierRoundingMode()); // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(3.5)); item.setQuantity(1); bill.addLineItem(item); // One line item Assert.assertEquals(1, bill.getLineItems().size()); // Do rounding RoundingUtil.handleRoundingLineItem(bill); // Now two line items Assert.assertEquals(2, bill.getLineItems().size()); // Assert rounding item's price BillLineItem rounding = bill.getLineItems().get(1); Assert.assertEquals(new BigDecimal(1.5), rounding.getTotal()); } /** * @verifies round bills with a non zero amount correctly for FLOOR * @see RoundingUtil#handleRoundingLineItem(Bill) */ @Test public void handleRoundingLineItem_shouldRoundBillsWithANonZeroAmountCorrectlyForFLOOR() throws Exception { CashierSettings settings = ModuleSettings.loadSettings(); settings.setCashierRoundingMode(CashierOptions.RoundingMode.FLOOR.toString()); ModuleSettings.saveSettings(settings); settings = ModuleSettings.loadSettings(); Assert.assertEquals(5, (int)settings.getCashierRoundingToNearest()); Assert.assertEquals(CashierOptions.RoundingMode.FLOOR.toString(), settings.getCashierRoundingMode()); // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(3.5)); item.setQuantity(1); bill.addLineItem(item); // One line item Assert.assertEquals(1, bill.getLineItems().size()); // Do rounding RoundingUtil.handleRoundingLineItem(bill); // Now two line items Assert.assertEquals(2, bill.getLineItems().size()); // Assert rounding item's price BillLineItem rounding = bill.getLineItems().get(1); Assert.assertEquals(new BigDecimal(-3.5), rounding.getTotal()); } /** * @see RoundingUtil#handleRoundingLineItem(Bill) * @verifies not modify a bill that needs no rounding */ @Test public void addRoundingLineItem_shouldNotModifyABillThatNeedsNoRounding() throws Exception { CashierOptions cashierOptions = cashOptService.getOptions(); Assert.assertEquals(5, (int)cashierOptions.getRoundToNearest()); // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(5)); item.setQuantity(1); bill.addLineItem(item); Assert.assertEquals(1, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(1, bill.getLineItems().size()); } @Test public void roundingInAdjustedBill_shouldNotAddRoundingLineItemIfRoundingDifferenceIsZero() throws Exception { // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(5)); item.setQuantity(1); bill.addLineItem(item); Assert.assertEquals(1, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(1, bill.getLineItems().size()); } @Test public void roundingInAdjustedBill_shouldAddRoundingLineItemIfRoundingDifferenceIsNotZero() throws Exception { // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(7)); item.setQuantity(1); bill.addLineItem(item); Assert.assertEquals(1, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(2, bill.getLineItems().size()); } @Test public void roundingInAdjustedBill_shouldUpdateRoundingLineItemIfRoundingDifferenceIsNotZero() throws Exception { // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(7)); item.setQuantity(1); bill.addLineItem(item); Assert.assertEquals(1, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(2, bill.getLineItems().size()); CashierOptions cashierOptions = cashOptService.getOptions(); IItemDataService itemService = Context.getService(IItemDataService.class); Item roundingItem = itemService.getByUuid(cashierOptions.getRoundingItemUuid()); BillLineItem roundingLineItem = null; for (BillLineItem lineItem : bill.getLineItems()) { if (roundingItem.equals(lineItem.getItem())) { roundingLineItem = lineItem; } } Assert.assertNotNull(roundingLineItem); Assert.assertEquals(roundingLineItem.getTotal().intValue(), -2); bill.addLineItem(item); Assert.assertEquals(3, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(3, bill.getLineItems().size()); roundingLineItem = null; for (BillLineItem lineItem : bill.getLineItems()) { if (roundingItem.equals(lineItem.getItem())) { roundingLineItem = lineItem; } } Assert.assertNotNull(roundingLineItem); Assert.assertEquals(roundingLineItem.getTotal().intValue(), 1); } @Test public void roundingInAdjustedBill_shouldDeleteRoundingLineItemIfRoundingDifferenceIsZero() throws Exception { // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(7)); item.setQuantity(1); bill.addLineItem(item); Assert.assertEquals(1, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(2, bill.getLineItems().size()); BillLineItem item2 = new BillLineItem(); item2.setItem(lineItemItem); item2.setLineItemOrder(0); item2.setPrice(new BigDecimal(3)); item2.setQuantity(1); bill.addLineItem(item2); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(2, bill.getLineItems().size()); CashierOptions cashierOptions = cashOptService.getOptions(); IItemDataService itemService = Context.getService(IItemDataService.class); Item roundingItem = itemService.getByUuid(cashierOptions.getRoundingItemUuid()); boolean containsRoundingItem = false; for (BillLineItem lineItem : bill.getLineItems()) { if (roundingItem.equals(lineItem.getItem())) { containsRoundingItem = true; } } Assert.assertEquals(false, containsRoundingItem); } @Test public void roundingInAdjustedBill_shouldConsiderRoundingOfPreviousBill() throws Exception { CashierOptions cashierOptions = cashOptService.getOptions(); Assert.assertEquals(5, (int)cashierOptions.getRoundToNearest()); // Test bill Bill bill = new Bill(); BillLineItem item = new BillLineItem(); Item lineItemItem = new Item(1); item.setItem(lineItemItem); item.setLineItemOrder(0); item.setPrice(new BigDecimal(8)); item.setQuantity(1); bill.addLineItem(item); IItemDataService itemService = Context.getService(IItemDataService.class); Item roundingItem = itemService.getByUuid(cashierOptions.getRoundingItemUuid()); Assert.assertEquals(1, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(2, bill.getLineItems().size()); item.setLineItemOrder(1); bill.addLineItem(item); Assert.assertEquals(3, bill.getLineItems().size()); RoundingUtil.handleRoundingLineItem(bill); Assert.assertEquals(3, bill.getLineItems().size()); BigDecimal roundingValue = new BigDecimal(0); BigDecimal itemTotal = new BigDecimal(0); int roundingItemCounter = 0; for (BillLineItem lineItem : bill.getLineItems()) { if (lineItem.getItem() != null && roundingItem.getId().equals(lineItem.getItem().getId())) { roundingValue = roundingValue.add(lineItem.getTotal()); roundingItemCounter++; } else { itemTotal = itemTotal.add(lineItem.getTotal()); } } Assert.assertEquals(16, itemTotal.intValue()); Assert.assertEquals(-1, roundingValue.intValue()); Assert.assertEquals(1, roundingItemCounter); } /** * @see RoundingUtil#round(java.math.BigDecimal, java.math.BigDecimal, CashierOptions.RoundingMode) * @verifies round to nearest */ @Test public void roundBillTotal_shouldRoundToNearest() throws Exception { Assert.assertEquals(new BigDecimal(5), RoundingUtil.round(new BigDecimal(3), 5, CashierOptions.RoundingMode.MID)); Assert.assertEquals(new BigDecimal(10), RoundingUtil.round(new BigDecimal(12), 5, CashierOptions.RoundingMode.MID)); } /** * @see RoundingUtil#round(java.math.BigDecimal, java.math.BigDecimal, CashierOptions.RoundingMode) * @verifies round to nearest ceiling */ @Test public void roundBillTotal_shouldRoundToNearestCeiling() throws Exception { Assert.assertEquals(new BigDecimal(5), RoundingUtil.round(new BigDecimal(1), 5, CashierOptions.RoundingMode.CEILING)); BigDecimal decimal = new BigDecimal(BigInteger.ONE, 2); // 0.01 Assert.assertEquals(new BigDecimal(1), RoundingUtil.round(decimal, 1, CashierOptions.RoundingMode.CEILING)); } /** * @see RoundingUtil#round(java.math.BigDecimal, java.math.BigDecimal, CashierOptions.RoundingMode) * @verifies round to nearest floor */ @Test public void roundBillTotal_shouldRoundToNearestFloor() throws Exception { Assert.assertEquals(new BigDecimal(5), RoundingUtil.round(new BigDecimal(9), 5, CashierOptions.RoundingMode.FLOOR)); BigDecimal decimal = new BigDecimal(BigInteger.valueOf(199), 2); // 1.99 Assert.assertEquals(new BigDecimal(1), RoundingUtil.round(decimal, 1, CashierOptions.RoundingMode.FLOOR)); } }