/*
*
* * Copyright © 2013 VillageReach. All Rights Reserved. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* *
* * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
package org.openlmis.rnr.domain;
import org.hamcrest.core.Is;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.mockito.Mock;
import org.openlmis.core.domain.*;
import org.openlmis.core.exception.DataException;
import org.openlmis.db.categories.UnitTests;
import org.openlmis.rnr.builder.RnrLineItemBuilder;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.natpryce.makeiteasy.MakeItEasy.*;
import static java.util.Arrays.asList;
import static junit.framework.Assert.assertEquals;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.openlmis.core.builder.ProductBuilder.code;
import static org.openlmis.core.builder.ProductBuilder.defaultProduct;
import static org.openlmis.core.builder.ProgramBuilder.defaultProgram;
import static org.openlmis.rnr.builder.RnrColumnBuilder.*;
import static org.openlmis.rnr.builder.RnrLineItemBuilder.*;
import static org.openlmis.rnr.domain.ProgramRnrTemplate.*;
import static org.openlmis.rnr.domain.ProgramRnrTemplate.NEW_PATIENT_COUNT;
import static org.openlmis.rnr.domain.RnRColumnSource.CALCULATED;
import static org.openlmis.rnr.domain.RnRColumnSource.USER_INPUT;
import static org.openlmis.rnr.domain.Rnr.RNR_VALIDATION_ERROR;
import static org.openlmis.rnr.domain.RnrStatus.AUTHORIZED;
import static org.openlmis.rnr.domain.RnrStatus.SUBMITTED;
import static org.powermock.api.mockito.PowerMockito.doNothing;
import static org.powermock.api.mockito.PowerMockito.spy;
@Category(UnitTests.class)
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(BlockJUnit4ClassRunner.class)
@PrepareForTest(RnrLineItem.class)
public class RnrLineItemTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
Integer numberOfMonths;
@Mock
ProgramRnrTemplate template;
@Mock
RnrColumn column;
private RnrLineItem lineItem;
private List<RnrColumn> templateColumns;
private List<LossesAndAdjustmentsType> lossesAndAdjustmentsList;
@Before
public void setUp() throws Exception {
templateColumns = new ArrayList<>();
addVisibleColumns(templateColumns);
lineItem = make(a(defaultRnrLineItem));
template = new ProgramRnrTemplate(getRnrColumns());
LossesAndAdjustmentsType additive1 = new LossesAndAdjustmentsType("TRANSFER_IN", "TRANSFER IN", true, 1);
LossesAndAdjustmentsType additive2 = new LossesAndAdjustmentsType("additive2", "Additive 2", true, 2);
LossesAndAdjustmentsType subtractive1 = new LossesAndAdjustmentsType("subtractive1", "Subtractive 1", false, 3);
LossesAndAdjustmentsType subtractive2 = new LossesAndAdjustmentsType("subtractive2", "Subtractive 2", false, 4);
lossesAndAdjustmentsList = asList(additive1, additive2, subtractive1, subtractive2);
numberOfMonths = 3;
}
@Test
public void shouldSetFieldValuesToNullIfSkipped() {
lineItem.setCalculatedOrderQuantity(null);
lineItem.setSkipped(true);
lineItem.setExpirationDate("some date");
lineItem.setFieldsForApproval();
assertThat(lineItem.getLossesAndAdjustments().size(), is(0));
assertThat(lineItem.getTotalLossesAndAdjustments(), is(0));
assertThat(lineItem.getQuantityDispensed(), is(nullValue()));
assertThat(lineItem.getBeginningBalance(), is(nullValue()));
assertThat(lineItem.getReasonForRequestedQuantity(), is(nullValue()));
assertThat(lineItem.getStockInHand(), is(nullValue()));
assertThat(lineItem.getStockOutDays(), is(nullValue()));
assertThat(lineItem.getNewPatientCount(), is(nullValue()));
assertThat(lineItem.getQuantityRequested(), is(nullValue()));
assertThat(lineItem.getQuantityApproved(), is(nullValue()));
assertThat(lineItem.getNormalizedConsumption(), is(nullValue()));
assertThat(lineItem.getPeriodNormalizedConsumption(), is(nullValue()));
assertThat(lineItem.getPacksToShip(), is(nullValue()));
assertThat(lineItem.getRemarks(), is(nullValue()));
assertThat(lineItem.getExpirationDate(), is(nullValue()));
assertThat(lineItem.getQuantityApproved(), is(nullValue()));
}
@Test
public void shouldConstructRnrLineItem() {
Program program = make(a(defaultProgram));
Product product = make(
a(defaultProduct, with(code, "ASPIRIN")));
product.setDispensingUnit("Strip");
ProductCategory category = new ProductCategory("C1", "Category 1", 3);
ProgramProduct programProduct = new ProgramProduct(program, product, 30, true);
programProduct.setDisplayOrder(9);
programProduct.setProductCategory(category);
programProduct.setFullSupply(product.getFullSupply());
RnrLineItem rnrLineItem = new RnrLineItem(1L, new FacilityTypeApprovedProduct("warehouse", programProduct, 3.2), 1L,
1L);
assertThat(rnrLineItem.getFullSupply(), is(programProduct.isFullSupply()));
assertThat(rnrLineItem.getMaxMonthsOfStock(), is(3.2));
assertThat(rnrLineItem.getRnrId(), is(1L));
assertThat(rnrLineItem.getDispensingUnit(), is("Strip"));
assertThat(rnrLineItem.getProductCode(), is("ASPIRIN"));
assertThat(rnrLineItem.getDosesPerMonth(), is(30));
assertThat(rnrLineItem.getModifiedBy(), is(1L));
assertThat(rnrLineItem.getDosesPerDispensingUnit(), is(10));
assertThat(rnrLineItem.getProductCategoryDisplayOrder(), is(3));
assertThat(rnrLineItem.getProductDisplayOrder(), is(9));
}
@Test
public void shouldThrowErrorIfBeginningBalanceNotPresent() throws Exception {
lineItem.setBeginningBalance(null);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowErrorIfBeginningBalanceIsNegative() throws Exception {
lineItem.setBeginningBalance(-678);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowErrorIfQuantityReceivedNotPresent() throws Exception {
lineItem.setQuantityReceived(null);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowErrorIfQuantityConsumedNotPresent() throws Exception {
lineItem.setQuantityDispensed(null);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowErrorIfNewPatientsNotPresent() throws Exception {
lineItem.setNewPatientCount(null);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowErrorIfStockOutDaysNotPresent() throws Exception {
lineItem.setStockOutDays(null);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowErrorIfStockInHandNotPresentAndIsUserInput() throws Exception {
lineItem.setStockInHand(null);
addColumnToTemplate(templateColumns, STOCK_IN_HAND, true, false);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldNotThrowErrorIfRequestedQuantityAndItsExplanationAreNull() throws Exception {
lineItem.setQuantityRequested(null);
lineItem.setReasonForRequestedQuantity(null);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldNotThrowErrorIfRequestedQuantityAndItsExplanationArePresent() {
lineItem.setQuantityRequested(123);
lineItem.setReasonForRequestedQuantity("something");
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowErrorIfRequestedQuantityIsPresentAndExplanationIsNotPresent() throws Exception {
lineItem.setQuantityRequested(70);
lineItem.setReasonForRequestedQuantity(null);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
ProgramRnrTemplate template = new ProgramRnrTemplate(templateColumns);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldNotThrowErrorIfRequestedQuantityIsNullAndExplanationIsPresent() {
lineItem.setQuantityRequested(null);
lineItem.setReasonForRequestedQuantity("something");
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldThrowExceptionIfCalculationForQuantityDispensedAndStockInHandNotValidAndFormulaValidatedTrue() throws Exception {
lineItem.setBeginningBalance(10);
lineItem.setQuantityReceived(3);
List<LossesAndAdjustments> list = Arrays.asList(createLossAndAdjustment("CLINIC_RETURN", true, 1));
lineItem.setLossesAndAdjustments(list);
lineItem.setStockInHand(4);
lineItem.setQuantityDispensed(9);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
lineItem.validateCalculatedFields(template);
}
@Test
public void shouldNotThrowExceptionIfCalculationForQuantityDispensedAndStockInHandValidAndFormulaValidatedTrue() throws Exception {
lineItem.setBeginningBalance(10);
lineItem.setQuantityReceived(3);
lineItem.setLossesAndAdjustments(asList(createLossAndAdjustment("", true, 1)));
lineItem.setStockInHand(4);
lineItem.setQuantityDispensed(10);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldNotThrowExceptionIfCalculationForQuantityDispensedAndStockInHandNotValidAndFormulaValidatedFalse() throws Exception {
lineItem.setBeginningBalance(10);
lineItem.setQuantityReceived(3);
lineItem.setTotalLossesAndAdjustments(1);
lineItem.setStockInHand(4);
lineItem.setQuantityDispensed(9);
templateColumns.get(0).setFormulaValidationRequired(false);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldNotThrowExceptionIfCalculationForQuantityDispensedAndStockInHandValidAndFormulaValidatedFalse() throws Exception {
lineItem.setBeginningBalance(10);
lineItem.setQuantityReceived(3);
lineItem.setTotalLossesAndAdjustments(1);
lineItem.setStockInHand(4);
lineItem.setQuantityDispensed(10);
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldCalculateAMCAndMaxStockQuantityAndOrderedQuantityOnlyWhenAuthorized() throws Exception {
RnrLineItem spyLineItem = spy(lineItem);
doNothing().when(spyLineItem).calculateNormalizedConsumption(template);
spyLineItem.calculateForFullSupply(template, AUTHORIZED, lossesAndAdjustmentsList, numberOfMonths);
verify(spyLineItem).calculateAmc(numberOfMonths);
verify(spyLineItem).calculateMaxStockQuantity(template);
verify(spyLineItem).calculateOrderQuantity();
}
@Test
public void shouldNotThrowErrorIfAllMandatoryFieldsPresent() throws Exception {
lineItem.validateMandatoryFields(template);
}
@Test
public void shouldCopyApproverEditableFields() throws Exception {
RnrLineItem editedLineItem = make(a(defaultRnrLineItem));
editedLineItem.setQuantityApproved(1872);
editedLineItem.setRemarks("Approved");
editedLineItem.setStockInHand(1946);
ProgramRnrTemplate template = new ProgramRnrTemplate(getRnrColumns());
lineItem.copyApproverEditableFields(editedLineItem, template);
assertThat(lineItem.getQuantityApproved(), is(1872));
assertThat(lineItem.getRemarks(), is("Approved"));
assertThat(lineItem.getStockInHand(), is(RnrLineItemBuilder.DEFAULT_STOCK_IN_HAND));
}
@Test
public void shouldCopyTotalLossesAndAdjustments() throws Exception {
RnrLineItem editedLineItem = make(a(defaultRnrLineItem));
editedLineItem.setTotalLossesAndAdjustments(10);
lineItem.copyCreatorEditableFieldsForFullSupply(editedLineItem, new ProgramRnrTemplate(getRnrColumns()));
assertThat(lineItem.getTotalLossesAndAdjustments(), is(10));
}
@Test
public void shouldCopyPreviousStockInHand() throws Exception {
RnrLineItem editedLineItem = make(a(defaultRnrLineItem));
editedLineItem.setPreviousStockInHand(10);
lineItem.copyCreatorEditableFieldsForFullSupply(editedLineItem, new ProgramRnrTemplate(getRnrColumns()));
assertThat(lineItem.getPreviousStockInHand(), is(10));
}
@Test
public void shouldCopyEditableFieldsForNonFullSupplyBasedOnTemplate() throws Exception {
lineItem.copyCreatorEditableFieldsForNonFullSupply(make(a(defaultRnrLineItem, with(quantityRequested, 9),
with(reasonForRequestedQuantity, "no reason"), with(remarks, "no remarks"))),
new ProgramRnrTemplate(getRnrColumnsForNonFullSupply()));
assertThat(lineItem.getReasonForRequestedQuantity(), is("no reason"));
assertThat(lineItem.getRemarks(), is("no remarks"));
assertThat(lineItem.getQuantityRequested(), is(9));
}
@Test
public void shouldCopyUserEditableFieldsOnlyIfVisible() throws Exception {
RnrLineItem editedLineItem = make(a(defaultRnrLineItem));
editedLineItem.setRemarks("Submitted");
editedLineItem.setBeginningBalance(12);
editedLineItem.setQuantityReceived(23);
editedLineItem.setQuantityDispensed(32);
editedLineItem.setStockInHand(1946);
editedLineItem.setNewPatientCount(1);
editedLineItem.setStockOutDays(7);
editedLineItem.setQuantityRequested(43);
editedLineItem.setReasonForRequestedQuantity("Reason");
List<LossesAndAdjustments> lossesAndAdjustments = new ArrayList<>();
editedLineItem.setLossesAndAdjustments(lossesAndAdjustments);
lineItem.copyCreatorEditableFieldsForFullSupply(editedLineItem, new ProgramRnrTemplate(getRnrColumns()));
assertThat(lineItem.getBeginningBalance(), is(RnrLineItemBuilder.DEFAULT_BEGINNING_BALANCE));
assertThat(lineItem.getStockOutDays(), is(RnrLineItemBuilder.STOCK_OUT_DAYS));
}
@Test
public void shouldThrowExceptionIfNonFullSupplyLineItemHasRequestedQuantityAsNull() {
Integer nullInteger = null;
RnrLineItem rnrLineItem = make(a(defaultRnrLineItem, with(quantityRequested, nullInteger)));
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
rnrLineItem.validateNonFullSupply();
}
@Test
public void shouldThrowExceptionIfNonFullSupplyLineItemHasRequestedQuantityIsNegative() {
RnrLineItem rnrLineItem = make(a(defaultRnrLineItem, with(quantityRequested, -10)));
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
rnrLineItem.validateNonFullSupply();
}
@Test
public void shouldThrowExceptionIfNonFullSupplyLineItemHasReasonForRequestedQuantityNull() {
String nullString = null;
RnrLineItem rnrLineItem = make(
a(defaultRnrLineItem, with(RnrLineItemBuilder.reasonForRequestedQuantity, nullString)));
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
rnrLineItem.validateNonFullSupply();
}
@Test
public void shouldCalculateCostAsZeroIfPacksToShipIsNull() {
Integer nullInteger = null;
RnrLineItem rnrLineItem = make(a(defaultRnrLineItem, with(packsToShip, nullInteger)));
Money money = rnrLineItem.calculateCost();
assertThat(money.getValue().intValue(), Is.is(0));
}
@Test
public void shouldCalculateCostIfPacksToShipIsNotNull() {
RnrLineItem rnrLineItem = make(a(defaultRnrLineItem, with(packsToShip, 5)));
Money money = rnrLineItem.calculateCost();
assertThat(money.getValue().intValue(), Is.is(20));
}
@Test
public void shouldCalculateStockInHandIfInputTypeIsCalculated() throws Exception {
RnrLineItem spyLineItem = spy(lineItem);
ArrayList<RnrColumn> columns = new ArrayList<RnrColumn>() {{
add(make(a(defaultRnrColumn, with(source, CALCULATED), with(columnName, STOCK_IN_HAND))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, QUANTITY_DISPENSED))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, NEW_PATIENT_COUNT),
with(option, new RnrColumnOption("newPatientCount", "NPC")))));
}};
ProgramRnrTemplate rnrTemplate = new ProgramRnrTemplate(columns);
spyLineItem.calculateForFullSupply(rnrTemplate, SUBMITTED, lossesAndAdjustmentsList, numberOfMonths);
verify(spyLineItem).calculateStockInHand();
verify(spyLineItem).calculateNormalizedConsumption(rnrTemplate);
verify(spyLineItem).calculatePeriodNormalizedConsumption(eq(numberOfMonths));
verify(spyLineItem).calculatePacksToShip();
}
@Test
public void shouldNotCalculateStockInHandIfUserInput() throws Exception {
RnrLineItem spyLineItem = spy(lineItem);
ArrayList<RnrColumn> columns = new ArrayList<RnrColumn>() {{
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, STOCK_IN_HAND))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, QUANTITY_DISPENSED))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, NEW_PATIENT_COUNT),
with(option, new RnrColumnOption("newPatientCount", "NPC")))));
}};
spyLineItem.calculateForFullSupply(new ProgramRnrTemplate(columns), SUBMITTED, lossesAndAdjustmentsList,
numberOfMonths);
verify(spyLineItem, never()).calculateStockInHand();
}
@Test
public void shouldCalculateQuantityDispensedIfCalculated() throws Exception {
RnrLineItem spyLineItem = spy(lineItem);
ArrayList<RnrColumn> columns = new ArrayList<RnrColumn>() {{
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, STOCK_IN_HAND))));
add(make(a(defaultRnrColumn, with(source, CALCULATED), with(columnName, QUANTITY_DISPENSED))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, NEW_PATIENT_COUNT),
with(option, new RnrColumnOption("newPatientCount", "NPC")))));
}};
spyLineItem.calculateForFullSupply(new ProgramRnrTemplate(columns), SUBMITTED, lossesAndAdjustmentsList,
numberOfMonths);
verify(spyLineItem).calculateQuantityDispensed();
}
@Test
public void shouldNotCalculateQuantityDispensedIfUserInput() throws Exception {
RnrLineItem spyLineItem = spy(lineItem);
ArrayList<RnrColumn> columns = new ArrayList<RnrColumn>() {{
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, STOCK_IN_HAND))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, QUANTITY_DISPENSED))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, NEW_PATIENT_COUNT),
with(option, new RnrColumnOption("newPatientCount", "NPC")))));
}};
spyLineItem.calculateForFullSupply(new ProgramRnrTemplate(columns), SUBMITTED, lossesAndAdjustmentsList,
numberOfMonths);
verify(spyLineItem, never()).calculateQuantityDispensed();
}
@Test
public void shouldNotCalculateOrderQuantityIfUserInput() throws Exception {
RnrLineItem spyLineItem = spy(lineItem);
ArrayList<RnrColumn> columns = new ArrayList<RnrColumn>() {{
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, STOCK_IN_HAND))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, QUANTITY_DISPENSED))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, CALCULATED_ORDER_QUANTITY))));
add(make(a(defaultRnrColumn, with(source, USER_INPUT), with(columnName, NEW_PATIENT_COUNT),
with(option, new RnrColumnOption("newPatientCount", "NPC")))));
}};
spyLineItem.calculateForFullSupply(new ProgramRnrTemplate(columns), AUTHORIZED, lossesAndAdjustmentsList,
numberOfMonths);
verify(spyLineItem, never()).calculateOrderQuantity();
}
@Test
public void shouldCopyBeginningBalanceIfItIsVisible() throws Exception {
RnrLineItem editedLineItem = make(a(defaultRnrLineItem));
editedLineItem.setBeginningBalance(44);
template.getRnrColumnsMap().get(BEGINNING_BALANCE).setVisible(true);
lineItem.copyCreatorEditableFieldsForFullSupply(editedLineItem, template);
assertThat(lineItem.getBeginningBalance(), is(editedLineItem.getBeginningBalance()));
}
@Test
public void shouldNotCopyQuantityApprovedWhileCopyingNonApproverEditableFields() throws Exception {
RnrLineItem editedLineItem = make(a(defaultRnrLineItem, with(quantityApproved, 89)));
lineItem.copyCreatorEditableFieldsForFullSupply(editedLineItem, new ProgramRnrTemplate(getRnrColumns()));
assertThat(lineItem.getQuantityApproved(), is(RnrLineItemBuilder.QUANTITY_APPROVED));
}
@Test
public void shouldValidateLineItemForApproval() throws Exception {
lineItem.setQuantityApproved(null);
expectedException.expect(DataException.class);
expectedException.expectMessage(RNR_VALIDATION_ERROR);
lineItem.validateForApproval();
}
@Test
public void shouldCalculatePacksToShipWhenPackRoundingThresholdIsSmallerThanRemainder() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(26);
lineItem.setPackSize(10);
lineItem.setPackRoundingThreshold(4);
lineItem.setRoundToZero(false);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(3));
}
@Test
public void shouldCalculatePacksToShipWhenPackRoundingThresholdIsGreaterThanRemainder() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(26);
lineItem.setPackSize(10);
lineItem.setPackRoundingThreshold(7);
lineItem.setRoundToZero(false);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(2));
}
@Test
public void shouldCalculatePacksToShipWhenCanRoundToZero() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(6);
lineItem.setPackSize(10);
lineItem.setPackRoundingThreshold(7);
lineItem.setRoundToZero(true);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(0));
}
@Test
public void shouldCalculatePacksToShipWhenCanNotRoundToZero() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(6);
lineItem.setPackSize(10);
lineItem.setPackRoundingThreshold(7);
lineItem.setRoundToZero(false);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(1));
}
@Test
public void shouldReturnNullPacksToShipIfPackSizeIsNull() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(6);
lineItem.setPackRoundingThreshold(7);
lineItem.setRoundToZero(true);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(nullValue()));
}
@Test
public void shouldReturnOnePackToShipIfOrderQuantityIsZeroAndRoundToZeroFalse() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(0);
lineItem.setPackSize(10);
lineItem.setRoundToZero(false);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(1));
}
@Test
public void shouldReturnZeroPackToShipIfOrderQuantityIsZeroAndRoundToZeroTrue() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(0);
lineItem.setPackSize(10);
lineItem.setRoundToZero(true);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(0));
}
@Test
public void shouldReturnZeroPackToShipIfOrderQuantityIsOneAndRoundToZeroTrueWithPackSizeTen() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setCalculatedOrderQuantity(1);
lineItem.setPackSize(10);
lineItem.setPackRoundingThreshold(7);
lineItem.setRoundToZero(true);
lineItem.calculatePacksToShip();
assertThat(lineItem.getPacksToShip(), is(0));
}
@Test
public void shouldCalculateMaxStockQuantity() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setMaxMonthsOfStock(2.4);
lineItem.setAmc(5);
lineItem.calculateMaxStockQuantity(template);
assertThat(lineItem.getMaxStockQuantity(), is(12));
}
@Test
public void shouldReturnOrderedQuantityZeroIfStockInHandExceedsMaxStockQuantity() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setMaxStockQuantity(10);
lineItem.setStockInHand(11);
lineItem.calculateOrderQuantity();
assertThat(lineItem.getCalculatedOrderQuantity(), is(0));
}
@Test
public void shouldReturnOrderedQuantityIfStockInHandIsLessThanMaxStockQuantity() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setMaxStockQuantity(11);
lineItem.setStockInHand(10);
lineItem.calculateOrderQuantity();
assertThat(lineItem.getCalculatedOrderQuantity(), is(1));
}
@Test
public void shouldReturnNullOrderedQuantityIfStockInHandNull() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setMaxStockQuantity(11);
lineItem.calculateOrderQuantity();
assertThat(lineItem.getCalculatedOrderQuantity(), is(nullValue()));
}
@Test
public void shouldSetQuantityApprovedEqualToOrderedQuantityIfFullSupply() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setFullSupply(true);
lineItem.setSkipped(false);
lineItem.setCalculatedOrderQuantity(10);
lineItem.setQuantityRequested(20);
lineItem.setFieldsForApproval();
assertThat(lineItem.getQuantityApproved(), is(20));
}
@Test
public void shouldSetQuantityApprovedEqualToRequestedQuantityIfNonFullSupply() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setFullSupply(false);
lineItem.setSkipped(false);
lineItem.setCalculatedOrderQuantity(10);
lineItem.setQuantityRequested(20);
lineItem.setFieldsForApproval();
assertThat(lineItem.getQuantityApproved(), is(20));
}
@Test
public void shouldCalculateQuantityDispensedIfAllInputPresent() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setBeginningBalance(1);
lineItem.setQuantityReceived(2);
lineItem.setTotalLossesAndAdjustments(3);
lineItem.setStockInHand(4);
lineItem.calculateQuantityDispensed();
assertThat(lineItem.getQuantityDispensed(), is(2));
}
@Test
public void shouldReturnNullQuantityDispensedIfAnyInputIsNull() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setBeginningBalance(1);
lineItem.setQuantityReceived(2);
lineItem.setTotalLossesAndAdjustments(3);
lineItem.setStockInHand(null);
lineItem.calculateQuantityDispensed();
assertThat(lineItem.getQuantityDispensed(), is(nullValue()));
}
@Test
public void shouldCalculateStockInHand() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setBeginningBalance(1);
lineItem.setQuantityReceived(2);
lineItem.setTotalLossesAndAdjustments(3);
lineItem.setQuantityDispensed(4);
lineItem.calculateStockInHand();
assertThat(lineItem.getStockInHand(), is(2));
}
@Test
public void shouldCalculateAmc() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setNormalizedConsumption(10);
lineItem.setPreviousNormalizedConsumptions(asList(10, 20));
lineItem.calculateAmc(1);
assertThat(lineItem.getAmc(), is(13));
}
@Test
public void shouldCalculatePeriodNC() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setNormalizedConsumption(10);
lineItem.calculatePeriodNormalizedConsumption(3);
assertThat(lineItem.getPeriodNormalizedConsumption(), is(30));
}
@Test
public void shouldCalculateNormalizedConsumptionForNewPatientCount() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setStockOutDays(1);
lineItem.setQuantityDispensed(2);
lineItem.setNewPatientCount(1);
lineItem.setDosesPerMonth(30);
lineItem.setDosesPerDispensingUnit(10);
lineItem.setReportingDays(30);
lineItem.calculateNormalizedConsumption(template);
assertThat(lineItem.getNormalizedConsumption(), is(5));
}
@Test
public void shouldCalculateNormalizedConsumptionForDispensingUnitsNewPatients() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setStockOutDays(1);
lineItem.setQuantityDispensed(2);
lineItem.setNewPatientCount(1);
lineItem.setDosesPerMonth(30);
lineItem.setDosesPerDispensingUnit(10);
lineItem.setReportingDays(30);
template.getRnrColumnsMap().get("newPatientCount").getConfiguredOption().setName("dispensingUnit");
lineItem.calculateNormalizedConsumption(template);
assertThat(lineItem.getNormalizedConsumption(), is(3));
}
@Test
public void shouldCalculateNCIfReportingDaysAreLessThanZero() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setStockOutDays(30);
lineItem.setQuantityDispensed(1);
lineItem.setNewPatientCount(1);
lineItem.setDosesPerMonth(30);
lineItem.setDosesPerDispensingUnit(10);
lineItem.setReportingDays(30);
lineItem.calculateNormalizedConsumption(template);
assertThat(lineItem.getNormalizedConsumption(), is(4));
}
@Test
public void shouldCalculateNCIfGIsZero() throws Exception {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setStockOutDays(0);
lineItem.setQuantityDispensed(1);
lineItem.setNewPatientCount(1);
lineItem.setDosesPerMonth(30);
lineItem.setDosesPerDispensingUnit(1);
lineItem.setReportingDays(30);
lineItem.calculateNormalizedConsumption(template);
assertThat(lineItem.getNormalizedConsumption(), is(31));
}
@Test
public void shouldSetBeginningBalanceWhenPreviousStockInHandAvailableAndColumnVisible() {
RnrLineItem lineItem = new RnrLineItem();
RnrLineItem previousRnrLineItem = new RnrLineItem();
previousRnrLineItem.setStockInHand(100);
lineItem.setBeginningBalanceWhenPreviousStockInHandAvailable(previousRnrLineItem, true);
assertThat(lineItem.getBeginningBalance(), is(100));
assertThat(lineItem.getPreviousStockInHand(), is(100));
}
@Test
public void shouldSetBeginningBalanceAsZeroWhenPreviousRnrLineItemSkippedAndColumnNotVisible() {
RnrLineItem lineItem = new RnrLineItem();
RnrLineItem previousRnrLineItem = new RnrLineItem();
previousRnrLineItem.setSkipped(true);
lineItem.setBeginningBalanceWhenPreviousStockInHandAvailable(previousRnrLineItem, false);
assertThat(lineItem.getBeginningBalance(), is(0));
assertThat(lineItem.getPreviousStockInHand(), is(nullValue()));
}
@Test
public void shouldSetBeginningBalanceAsZeroWhenPreviousRnrLineItemNotAvailableAndColumnVisible() {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setBeginningBalanceWhenPreviousStockInHandAvailable(null, true);
assertThat(lineItem.getBeginningBalance(), is(0));
assertThat(lineItem.getPreviousStockInHand(), is(nullValue()));
}
@Test
public void shouldSetBeginningBalanceAsZeroWhenPreviousRnrLineItemNotAvailableAndColumnNotVisible() {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setBeginningBalanceWhenPreviousStockInHandAvailable(null, false);
assertThat(lineItem.getBeginningBalance(), is(0));
assertThat(lineItem.getPreviousStockInHand(), is(nullValue()));
}
@Test
public void shouldNotUpdateTotalLossesAndAdjustmentsFieldIfLossesAndAdjustmentsAreNullAndTotalHaveValue() {
RnrLineItem lineItem = new RnrLineItem();
lineItem.setTotalLossesAndAdjustments(10);
lineItem.calculateTotalLossesAndAdjustments(new ArrayList<LossesAndAdjustmentsType>());
assertEquals(10, lineItem.getTotalLossesAndAdjustments().intValue());
}
private ArrayList<RnrColumn> getRnrColumns() {
return new ArrayList<RnrColumn>() {{
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.QUANTITY_RECEIVED), with(visible, false))));
add(make(a(defaultRnrColumn, with(columnName, QUANTITY_DISPENSED), with(visible, false),
with(source, CALCULATED))));
add(make(a(defaultRnrColumn, with(columnName, LOSSES_AND_ADJUSTMENTS), with(visible, true))));
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.NEW_PATIENT_COUNT), with(visible, false),
with(option, new RnrColumnOption("newPatientCount", "NPC")))));
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.NEW_PATIENT_COUNT), with(visible, false), with(option, new RnrColumnOption(ProgramRnrTemplate.NEW_PATIENT_COUNT, ProgramRnrTemplate.NEW_PATIENT_COUNT) ) )));
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.STOCK_OUT_DAYS), with(visible, false))));
add(make(a(defaultRnrColumn, with(columnName, STOCK_IN_HAND), with(visible, false),
with(source, CALCULATED))));
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.BEGINNING_BALANCE), with(visible, false))));
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.REMARKS), with(visible, true),
with(source, USER_INPUT))));
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.QUANTITY_APPROVED), with(visible, true),
with(source, USER_INPUT))));
}};
}
private ArrayList<RnrColumn> getRnrColumnsForNonFullSupply() {
return new ArrayList<RnrColumn>() {{
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.QUANTITY_REQUESTED), with(visible, true),
with(source, USER_INPUT))));
add(make(a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.REMARKS), with(visible, true),
with(source, USER_INPUT))));
add(make(
a(defaultRnrColumn, with(columnName, ProgramRnrTemplate.REASON_FOR_REQUESTED_QUANTITY), with(visible, true),
with(source, USER_INPUT))));
}};
}
private void addVisibleColumns(List<RnrColumn> templateColumns) {
addColumnToTemplate(templateColumns, ProgramRnrTemplate.BEGINNING_BALANCE, true, true);
addColumnToTemplate(templateColumns, QUANTITY_DISPENSED, true, null);
addColumnToTemplate(templateColumns, ProgramRnrTemplate.QUANTITY_RECEIVED, true, null);
addColumnToTemplate(templateColumns, ProgramRnrTemplate.NEW_PATIENT_COUNT, true, null);
addColumnToTemplate(templateColumns, ProgramRnrTemplate.STOCK_OUT_DAYS, true, null);
addColumnToTemplate(templateColumns, ProgramRnrTemplate.QUANTITY_REQUESTED, true, null);
addColumnToTemplate(templateColumns, ProgramRnrTemplate.REASON_FOR_REQUESTED_QUANTITY, true, null);
}
private void addColumnToTemplate(List<RnrColumn> templateColumns,
String columnName,
Boolean visible,
Boolean formulaValidation) {
RnrColumn rnrColumn = new RnrColumn();
rnrColumn.setName(columnName);
rnrColumn.setVisible(visible);
if (formulaValidation != null) rnrColumn.setFormulaValidationRequired(formulaValidation);
templateColumns.add(rnrColumn);
}
private LossesAndAdjustments createLossAndAdjustment(String typeName, boolean additive, int quantity) {
LossesAndAdjustments lossAndAdjustment = new LossesAndAdjustments();
LossesAndAdjustmentsType lossesAndAdjustmentsType = new LossesAndAdjustmentsType();
lossesAndAdjustmentsType.setName(typeName);
lossesAndAdjustmentsType.setAdditive(additive);
lossAndAdjustment.setType(lossesAndAdjustmentsType);
lossAndAdjustment.setQuantity(quantity);
return lossAndAdjustment;
}
}