package org.openlmis.core.model.service; import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.openlmis.core.LMISRepositoryUnitTest; import org.openlmis.core.LMISTestApp; import org.openlmis.core.LMISTestRunner; import org.openlmis.core.exceptions.LMISException; import org.openlmis.core.manager.MovementReasonManager; import org.openlmis.core.manager.SharedPreferenceMgr; import org.openlmis.core.model.Cmm; import org.openlmis.core.model.Product; import org.openlmis.core.model.StockCard; import org.openlmis.core.model.StockMovementItem; import org.openlmis.core.model.repository.CmmRepository; import org.openlmis.core.model.repository.StockRepository; import org.openlmis.core.utils.DateUtil; import org.robolectric.RuntimeEnvironment; import java.util.Date; import java.util.List; import roboguice.RoboGuice; import static java.util.Arrays.asList; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.openlmis.core.manager.MovementReasonManager.MovementType.ISSUE; import static org.openlmis.core.manager.MovementReasonManager.MovementType.RECEIVE; @RunWith(LMISTestRunner.class) public class StockServiceTest extends LMISRepositoryUnitTest { StockService stockService; private Date lastFirstMonthDate; private Date lastSecondMonthDate; private Date lastThirdMonthDate; private Date lastForthMonthDate; private StockCard stockCard; private StockRepository mockedStockRepository; private CmmRepository mockedCmmRepository; @Before public void setup() throws LMISException { mockedStockRepository = mock(StockRepository.class); mockedCmmRepository = mock(CmmRepository.class); stockService = RoboGuice.getInjector(RuntimeEnvironment.application).getInstance(StockService.class); Date today = DateUtil.today(); lastFirstMonthDate = DateUtil.generatePreviousMonthDateBy(today); lastSecondMonthDate = DateUtil.generatePreviousMonthDateBy(lastFirstMonthDate); lastThirdMonthDate = DateUtil.generatePreviousMonthDateBy(lastSecondMonthDate); lastForthMonthDate = DateUtil.generatePreviousMonthDateBy(lastThirdMonthDate); stockCard = new StockCard(); } @Test public void shouldUpdateAverageMonthlyConsumption() throws Exception { List<StockCard> list = asList(new StockCard()); stockService = spy(stockService); stockService.stockRepository = mockedStockRepository; stockService.cmmRepository = mockedCmmRepository; when(mockedStockRepository.list()).thenReturn(list); doReturn(0F).when(stockService).calculateAverageMonthlyConsumption(any(StockCard.class)); stockService.monthlyUpdateAvgMonthlyConsumption(); verify(mockedStockRepository).createOrUpdate(any(StockCard.class)); verify(mockedCmmRepository).save(any(Cmm.class)); } @Test public void shouldNotUpdateAverageMonthlyConsumption() throws Exception { LMISTestApp.getInstance().setCurrentTimeMillis(new DateTime().getMillis()); SharedPreferenceMgr.getInstance().updateLatestLowStockAvgTime(); List<StockCard> list = asList(new StockCard()); stockService.stockRepository = mockedStockRepository; stockService.cmmRepository = mockedCmmRepository; when(mockedStockRepository.list()).thenReturn(list); stockService.monthlyUpdateAvgMonthlyConsumption(); verify(mockedStockRepository, never()).createOrUpdate(any(StockCard.class)); verify(mockedCmmRepository, never()).save(any(Cmm.class)); } @Test public void shouldCalculateAverageMonthlyConsumptionWithStockOutCorrectly() throws LMISException { //given StockCard stockCard = new StockCard(); stockCard.setStockOnHand(200); stockService.stockRepository.createOrUpdate(stockCard); createMovementItem(ISSUE, 100, stockCard, new Date(), lastForthMonthDate, false);//4 month ago soh:100 createMovementItem(ISSUE, 100, stockCard, new Date(), lastThirdMonthDate, false);//3 month ago soh:0 createMovementItem(RECEIVE, 400, stockCard, new Date(), lastSecondMonthDate, false);//2 month ago soh:400 createMovementItem(ISSUE, 100, stockCard, new Date(), lastSecondMonthDate, false);//2 month ago soh:300 createMovementItem(ISSUE, 100, stockCard, new Date(), lastFirstMonthDate, false);//1 month ago soh:200 //when float averageMonthlyConsumption = stockService.calculateAverageMonthlyConsumption(stockCard); //then assertThat(averageMonthlyConsumption, is(100F)); } @Test public void shouldCalculateAverageMonthlyConsumptionWithContinuedStockOutCorrectly() throws LMISException { //given StockCard stockCard = new StockCard(); stockCard.setStockOnHand(200); stockService.stockRepository.createOrUpdate(stockCard); createMovementItem(ISSUE, 100, stockCard, new Date(), lastForthMonthDate, false);//4 month ago soh:100 createMovementItem(ISSUE, 100, stockCard, new Date(), lastForthMonthDate, false);//4 month ago soh:0 //3 month ago: no movement, so it inherits the stock out status of 4 month ago createMovementItem(RECEIVE, 400, stockCard, new Date(), lastSecondMonthDate, false);//2 month ago soh:400 createMovementItem(ISSUE, 100, stockCard, new Date(), lastSecondMonthDate, false);//2 month ago soh:300 createMovementItem(ISSUE, 100, stockCard, new Date(), lastFirstMonthDate, false);//1 month ago soh:200 //when float averageMonthlyConsumption = stockService.calculateAverageMonthlyConsumption(stockCard); //then assertThat(averageMonthlyConsumption, is(-1F)); } private StockMovementItem createMovementItem(MovementReasonManager.MovementType type, long quantity, StockCard stockCard, Date createdTime, Date movementDate, boolean synced) throws LMISException { StockMovementItem stockMovementItem = new StockMovementItem(); stockMovementItem.setMovementQuantity(quantity); stockMovementItem.setMovementType(type); stockMovementItem.setMovementDate(movementDate); stockMovementItem.setStockCard(stockCard); stockMovementItem.setSynced(synced); LMISTestApp.getInstance().setCurrentTimeMillis(createdTime.getTime()); if (stockMovementItem.isPositiveMovement()) { stockMovementItem.setStockOnHand(stockCard.getStockOnHand() + quantity); } else { stockMovementItem.setStockOnHand(stockCard.getStockOnHand() - quantity); } stockCard.setStockOnHand(stockMovementItem.getStockOnHand()); stockService.stockRepository.addStockMovementAndUpdateStockCard(stockMovementItem); stockService.stockRepository.refresh(stockCard); return stockMovementItem; } @Test public void shouldCalculateAverageMonthlyConsumptionLessThanZeroWhenOnlyTwoValidPeriod() throws Exception { StockCard stockCard = new StockCard(); stockCard.setStockOnHand(300); stockService.stockRepository.createOrUpdate(stockCard); createMovementItem(ISSUE, 100, stockCard, new Date(), lastFirstMonthDate, false); createMovementItem(ISSUE, 100, stockCard, new Date(), lastSecondMonthDate, false); float averageMonthlyConsumption = stockService.calculateAverageMonthlyConsumption(stockCard); assertEquals(2, stockService.stockMovementRepository.listLastFiveStockMovements(stockCard.getId()).size()); assertThat(-1F, is(averageMonthlyConsumption)); } @Test public void shouldCalculateAverageMonthlyConsumptionLessThanZeroWhenThereIsNoStockMovement() throws Exception { Product product = new Product(); product.setId(1L); product.setPrimaryName("product"); StockCard stockCard = new StockCard(); stockCard.setStockOnHand(300); stockCard.setProduct(product); stockService.stockRepository.createOrUpdate(stockCard); float averageMonthlyConsumption = stockService.calculateAverageMonthlyConsumption(stockCard); assertThat(-1F, is(averageMonthlyConsumption)); } @Test public void shouldCalculateAverageMonthlyConsumptionCorrectly() throws Exception { stockCard.setStockOnHand(400); stockService.stockRepository.createOrUpdate(stockCard); createMovementItem(ISSUE, 100, stockCard, new Date(), lastFirstMonthDate, false); createMovementItem(ISSUE, 100, stockCard, new Date(), lastSecondMonthDate, false); createMovementItem(ISSUE, 100, stockCard, new Date(), lastThirdMonthDate, false); float averageMonthlyConsumption = stockService.calculateAverageMonthlyConsumption(stockCard); assertEquals(3, stockService.stockMovementRepository.listLastFiveStockMovements(stockCard.getId()).size()); assertThat(100F, is(averageMonthlyConsumption)); } @Test public void shouldCalculateAverageMonthlyConsumptionLessThanZeroWhenLastMonthSOHIsZero() throws Exception { stockCard.setStockOnHand(300); stockService.stockRepository.createOrUpdate(stockCard); createMovementItem(ISSUE, 100, stockCard, new Date(), lastFirstMonthDate, false); createMovementItem(ISSUE, 100, stockCard, new Date(), lastSecondMonthDate, false); createMovementItem(ISSUE, 100, stockCard, new Date(), lastThirdMonthDate, false); float averageMonthlyConsumption = stockService.calculateAverageMonthlyConsumption(stockCard); assertEquals(3, stockService.stockMovementRepository.listLastFiveStockMovements(stockCard.getId()).size()); assertThat(-1F, is(averageMonthlyConsumption)); } @Test public void shouldCalculateAverageMonthlyConsumptionWhenLastMonthHaveNoStockItem() throws Exception { stockCard.setStockOnHand(400); stockService.stockRepository.createOrUpdate(stockCard); createMovementItem(ISSUE, 100, stockCard, new Date(), lastFirstMonthDate, false); createMovementItem(ISSUE, 100, stockCard, new Date(), lastThirdMonthDate, false); createMovementItem(ISSUE, 100, stockCard, new Date(), lastForthMonthDate, false); float averageMonthlyConsumption = stockService.calculateAverageMonthlyConsumption(stockCard); assertEquals(3, stockService.stockMovementRepository.listLastFiveStockMovements(stockCard.getId()).size()); assertThat(200F / 3, is(averageMonthlyConsumption)); } }