diff --git a/build.sh b/build.sh index 41d2fed9..de036928 100755 --- a/build.sh +++ b/build.sh @@ -7,4 +7,4 @@ --source-file src/main/resources/messages_en.properties # Run Gradle build -gradle clean build +gradle clean build integrationTest diff --git a/src/integration-test/java/org/openlmis/stockmanagement/repository/CalculatedStockOnHandRepositoryIntegrationTest.java b/src/integration-test/java/org/openlmis/stockmanagement/repository/CalculatedStockOnHandRepositoryIntegrationTest.java index c38a9213..de20197e 100644 --- a/src/integration-test/java/org/openlmis/stockmanagement/repository/CalculatedStockOnHandRepositoryIntegrationTest.java +++ b/src/integration-test/java/org/openlmis/stockmanagement/repository/CalculatedStockOnHandRepositoryIntegrationTest.java @@ -25,7 +25,6 @@ import java.time.LocalDate; import java.util.List; import java.util.UUID; - import org.junit.Test; import org.openlmis.stockmanagement.domain.card.StockCard; import org.openlmis.stockmanagement.domain.event.CalculatedStockOnHand; @@ -61,18 +60,18 @@ CalculatedStockOnHand generateInstance() { private CalculatedStockOnHand generateInstance(UUID facility, UUID program, UUID product, UUID lot) { StockEvent event = new StockEventDataBuilder() - .withoutId() - .withFacility(facility) - .withProgram(program) - .build(); + .withoutId() + .withFacility(facility) + .withProgram(program) + .build(); event = stockEventsRepository.save(event); StockCard stockCard = new StockCardDataBuilder(event) - .withoutId() - .withOrderable(product) - .withLot(lot) - .build(); + .withoutId() + .withOrderableId(product) + .withLotId(lot) + .build(); stockCard = stockCardRepository.save(stockCard); @@ -97,42 +96,42 @@ public void shouldReturnCalculatedStockOnHandsWhenNoStartDateProvided() { calculatedStockOnHandRepository.save(calculatedStockOnHand3); List resultList1 = calculatedStockOnHandRepository - .findByStockCardIdInAndOccurredDateLessThanEqual( - asList(calculatedStockOnHand1.getStockCard().getId(), - calculatedStockOnHand2.getStockCard().getId(), - calculatedStockOnHand3.getStockCard().getId()), - LocalDate.of(2010, 11, 1)); + .findByStockCardIdInAndOccurredDateLessThanEqual( + asList(calculatedStockOnHand1.getStockCard().getId(), + calculatedStockOnHand2.getStockCard().getId(), + calculatedStockOnHand3.getStockCard().getId()), + LocalDate.of(2010, 11, 1)); assertThat(resultList1, hasItems(calculatedStockOnHand1, - calculatedStockOnHand2, calculatedStockOnHand3)); + calculatedStockOnHand2, calculatedStockOnHand3)); assertEquals(resultList1.size(), 3); List resultList2 = calculatedStockOnHandRepository - .findByStockCardIdInAndOccurredDateLessThanEqual( - asList(calculatedStockOnHand1.getStockCard().getId(), - calculatedStockOnHand2.getStockCard().getId(), - calculatedStockOnHand3.getStockCard().getId()), - LocalDate.of(2010, 9, 15)); + .findByStockCardIdInAndOccurredDateLessThanEqual( + asList(calculatedStockOnHand1.getStockCard().getId(), + calculatedStockOnHand2.getStockCard().getId(), + calculatedStockOnHand3.getStockCard().getId()), + LocalDate.of(2010, 9, 15)); assertThat(resultList2, hasItems(calculatedStockOnHand1, calculatedStockOnHand2)); assertEquals(resultList2.size(), 2); List resultList3 = calculatedStockOnHandRepository - .findByStockCardIdInAndOccurredDateLessThanEqual( - asList(calculatedStockOnHand1.getStockCard().getId(), - calculatedStockOnHand2.getStockCard().getId(), - calculatedStockOnHand3.getStockCard().getId()), - LocalDate.of(2010, 8, 15)); + .findByStockCardIdInAndOccurredDateLessThanEqual( + asList(calculatedStockOnHand1.getStockCard().getId(), + calculatedStockOnHand2.getStockCard().getId(), + calculatedStockOnHand3.getStockCard().getId()), + LocalDate.of(2010, 8, 15)); assertThat(resultList3, hasItems(calculatedStockOnHand1)); assertEquals(resultList3.size(), 1); List resultList4 = calculatedStockOnHandRepository - .findByStockCardIdInAndOccurredDateLessThanEqual( - asList(calculatedStockOnHand1.getStockCard().getId(), - calculatedStockOnHand2.getStockCard().getId(), - calculatedStockOnHand3.getStockCard().getId()), - LocalDate.of(2010, 4, 15)); + .findByStockCardIdInAndOccurredDateLessThanEqual( + asList(calculatedStockOnHand1.getStockCard().getId(), + calculatedStockOnHand2.getStockCard().getId(), + calculatedStockOnHand3.getStockCard().getId()), + LocalDate.of(2010, 4, 15)); assertTrue(resultList4.isEmpty()); assertEquals(resultList4.size(), 0); diff --git a/src/integration-test/java/org/openlmis/stockmanagement/repository/StockCardRepositoryIntegrationTest.java b/src/integration-test/java/org/openlmis/stockmanagement/repository/StockCardRepositoryIntegrationTest.java index eaa50364..7da6c870 100644 --- a/src/integration-test/java/org/openlmis/stockmanagement/repository/StockCardRepositoryIntegrationTest.java +++ b/src/integration-test/java/org/openlmis/stockmanagement/repository/StockCardRepositoryIntegrationTest.java @@ -94,8 +94,8 @@ private StockCard generateInstance(UUID facility, UUID program, UUID product, UU StockCard stockCard = new StockCardDataBuilder(event) .withoutId() - .withOrderable(product) - .withLot(lot) + .withOrderableId(product) + .withLotId(lot) .withLineItem(lineItem) .withIsActive(true) .build(); diff --git a/src/integration-test/java/org/openlmis/stockmanagement/service/CalculatedStockOnHandServiceIntegrationTest.java b/src/integration-test/java/org/openlmis/stockmanagement/service/CalculatedStockOnHandServiceIntegrationTest.java index ff8e9505..16d92ca1 100644 --- a/src/integration-test/java/org/openlmis/stockmanagement/service/CalculatedStockOnHandServiceIntegrationTest.java +++ b/src/integration-test/java/org/openlmis/stockmanagement/service/CalculatedStockOnHandServiceIntegrationTest.java @@ -770,8 +770,8 @@ private StockEvent prepareEvent(UUID facility, UUID program) { private StockCard prepareStockCard(StockEvent event, UUID product, UUID lot) { StockCard result = new StockCardDataBuilder(event) .withoutId() - .withOrderable(product) - .withLot(lot) + .withOrderableId(product) + .withLotId(lot) .build(); return stockCardRepository.save(result); } diff --git a/src/integration-test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceIntegrationTest.java b/src/integration-test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceIntegrationTest.java index c24b02a2..66d1103d 100644 --- a/src/integration-test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceIntegrationTest.java +++ b/src/integration-test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceIntegrationTest.java @@ -57,6 +57,7 @@ import org.openlmis.stockmanagement.service.referencedata.OrderableReferenceDataService; import org.openlmis.stockmanagement.service.referencedata.ProgramReferenceDataService; import org.openlmis.stockmanagement.testutils.StockEventDataBuilder; +import org.slf4j.profiler.Profiler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -115,11 +116,9 @@ public void shouldFindExistingStockCards() OrderableDto orderable3 = createOrderableDto(orderable3Id, ""); OrderableDto orderable4 = createOrderableDto(orderable4Id, ""); - when(orderableReferenceDataService - .findAll()) + when(orderableReferenceDataService.findByIds(any())) .thenReturn(asList(orderable1, orderable2, orderable3, orderable4)); - when(lotReferenceDataService.getAllLotsOf(any(UUID.class))) - .thenReturn(emptyList()); + when(lotReferenceDataService.findByIds(any())).thenReturn(emptyList()); when(facilityReferenceDataService.findOne(any(UUID.class))) .thenReturn(new FacilityDto()); when(programReferenceDataService.findOne(any(UUID.class))) @@ -169,7 +168,7 @@ public void shouldReturnPageOfStockCards() throws Exception { PageRequest pageRequest = PageRequest.of(0, 1); //when Page stockCards = stockCardSummariesService - .findStockCards(programId, facilityId, pageRequest); + .findStockCards(programId, facilityId, pageRequest, new Profiler("TEST")); //then assertThat(stockCards.getContent().size(), is(1)); diff --git a/src/integration-test/java/org/openlmis/stockmanagement/web/StockCardControllerIntegrationTest.java b/src/integration-test/java/org/openlmis/stockmanagement/web/StockCardControllerIntegrationTest.java index 77c5d99a..dec0fd8a 100644 --- a/src/integration-test/java/org/openlmis/stockmanagement/web/StockCardControllerIntegrationTest.java +++ b/src/integration-test/java/org/openlmis/stockmanagement/web/StockCardControllerIntegrationTest.java @@ -17,6 +17,7 @@ import static java.util.Collections.singletonList; import static org.hamcrest.Matchers.hasSize; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -32,7 +33,6 @@ import com.google.common.collect.ImmutableSet; import java.util.UUID; - import org.junit.Test; import org.openlmis.stockmanagement.dto.StockCardDto; import org.openlmis.stockmanagement.exception.PermissionMessageException; @@ -42,6 +42,7 @@ import org.openlmis.stockmanagement.service.StockCardSummariesService; import org.openlmis.stockmanagement.testutils.StockCardDtoDataBuilder; import org.openlmis.stockmanagement.util.Message; +import org.slf4j.profiler.Profiler; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; @@ -146,7 +147,7 @@ public void shouldGetPagedStockCardSummariesWhenPermissionIsGranted() throws Exc PageRequest pageable = PageRequest.of(0, 20); when(stockCardSummariesService - .findStockCards(programId, facilityId, pageable)) + .findStockCards(eq(programId), eq(facilityId), eq(pageable), any(Profiler.class))) .thenReturn(new PageImpl<>(singletonList(StockCardDtoDataBuilder.createStockCardDto()))); ResultActions resultActions = mvc.perform( @@ -215,4 +216,4 @@ public void shouldReturn404WhenStockCardNotFoundWhileMakingInactive() throws Exc // then resultActions.andExpect(status().isNotFound()); } -} \ No newline at end of file +} diff --git a/src/main/java/org/openlmis/stockmanagement/domain/event/StockEvent.java b/src/main/java/org/openlmis/stockmanagement/domain/event/StockEvent.java index c0e1e71a..425632ec 100644 --- a/src/main/java/org/openlmis/stockmanagement/domain/event/StockEvent.java +++ b/src/main/java/org/openlmis/stockmanagement/domain/event/StockEvent.java @@ -27,6 +27,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.ToString; import org.openlmis.stockmanagement.domain.BaseEntity; @Entity @@ -54,6 +55,7 @@ public class StockEvent extends BaseEntity { private String documentNumber; + @ToString.Exclude @OneToMany(cascade = ALL, mappedBy = "stockEvent") private List lineItems; } diff --git a/src/main/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionService.java b/src/main/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionService.java index c08cc9db..3b27f1fd 100644 --- a/src/main/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionService.java +++ b/src/main/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionService.java @@ -28,6 +28,9 @@ @Service public class HomeFacilityPermissionService { + + static final String WS_TYPE_CODE = "WS"; + @Autowired private AuthenticationHelper authenticationHelper; @@ -54,7 +57,28 @@ public void checkProgramSupported(UUID programId) { } } + /** + * Returns true if facility is within the same geographic zone as the home facility. + * Returns false otherwise or in case facility id is equal to home facility id. + * + * @param facilityId UUID of facility + * @return boolean flag indicating linkage between facility and home facility + */ + public boolean checkFacilityAndHomeFacilityLinkage(UUID facilityId) { + UUID homeFacilityId = authenticationHelper.getCurrentUser().getHomeFacilityId(); + if (facilityId.equals(homeFacilityId)) { + return false; + } + FacilityDto facility = facilityService.findOne(facilityId); + if (facility.getType().getCode().equals(WS_TYPE_CODE)) { + FacilityDto homeFacility = facilityService.findOne(homeFacilityId); + return homeFacility.getGeographicZone().getId().equals(facility.getGeographicZone().getId()); + } else { + return false; + } + } + private void throwException(String errorKey, String... params) { throw new PermissionMessageException(new Message(errorKey, (Object)params)); } -} \ No newline at end of file +} diff --git a/src/main/java/org/openlmis/stockmanagement/service/StockCardSummariesService.java b/src/main/java/org/openlmis/stockmanagement/service/StockCardSummariesService.java index b53eb2ca..a85a6655 100644 --- a/src/main/java/org/openlmis/stockmanagement/service/StockCardSummariesService.java +++ b/src/main/java/org/openlmis/stockmanagement/service/StockCardSummariesService.java @@ -16,13 +16,13 @@ package org.openlmis.stockmanagement.service; import static java.util.Collections.emptyList; +import static java.util.function.Function.identity; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; import static java.util.stream.Stream.concat; import static java.util.stream.Stream.empty; import static org.apache.commons.collections.CollectionUtils.isEmpty; -import static org.openlmis.stockmanagement.domain.identity.OrderableLotIdentity.identityOf; import java.time.LocalDate; import java.util.ArrayList; @@ -30,11 +30,13 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import java.util.stream.Stream; - +import lombok.AllArgsConstructor; import lombok.Getter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -95,6 +97,9 @@ public class StockCardSummariesService extends StockCardBaseService { @Autowired private PermissionService permissionService; + @Autowired + private HomeFacilityPermissionService homeFacilityPermissionService; + /** * Get a map of stock cards assigned to orderable ids. * Stock cards are grouped using orderable fulfills endpoint. @@ -105,8 +110,11 @@ public class StockCardSummariesService extends StockCardBaseService { * @param orderableIds collection of unique orderable UUIDs * @return map of stock cards assigned to orderable ids */ - public Map getGroupedStockCards(UUID programId, UUID facilityId, - Set orderableIds, LocalDate startDate, LocalDate endDate) { + public Map getGroupedStockCards(UUID programId, + UUID facilityId, + Set orderableIds, + LocalDate startDate, + LocalDate endDate) { List stockCards = calculatedStockOnHandService .getStockCardsWithStockOnHand(programId, facilityId); @@ -138,8 +146,11 @@ public StockCardSummaries findStockCards(StockCardSummariesV2SearchParams params Profiler profiler = new Profiler("FIND_STOCK_CARD_SUMMARIES_FOR_PARAMS"); profiler.setLogger(LOGGER); - profiler.start("VALIDATE_VIEW_RIGHTS"); - permissionService.canViewStockCard(params.getProgramId(), params.getFacilityId()); + if (!homeFacilityPermissionService + .checkFacilityAndHomeFacilityLinkage(params.getFacilityId())) { + profiler.start("VALIDATE_VIEW_RIGHTS"); + permissionService.canViewStockCard(params.getProgramId(), params.getFacilityId()); + } profiler.start("GET_APPROVED_PRODUCTS"); OrderablesAggregator approvedProducts = approvedProductReferenceDataService @@ -184,8 +195,8 @@ public StockCardSummaries findStockCards(StockCardSummariesV2SearchParams params // FIXME: Fix page retrieving/calculation, // page size may be wrong when there are orderables matching not only by lot codes List stockCards = calculatedStockOnHandService.getStockCardsWithStockOnHand( - params.getProgramId(), params.getFacilityId(), params.getAsOfDate(), - orderableIdsForStockCard, lotCodeIds); + params.getProgramId(), params.getFacilityId(), params.getAsOfDate(), + orderableIdsForStockCard, lotCodeIds); Page orderablesPage = approvedProducts.getOrderablesPage(); StockCardSummaries result = new StockCardSummaries( @@ -216,10 +227,13 @@ public List findStockCards(UUID programId, UUID facilityId) { * @param pageable page object. * @return page of stock cards. */ - public Page findStockCards(UUID programId, UUID facilityId, Pageable pageable) { + public Page findStockCards(UUID programId, UUID facilityId, Pageable pageable, + Profiler profiler) { + profiler.start("FIND_BY_PROGRAM_AND_FACILITY"); Page pageOfCards = stockCardRepository .findByProgramIdAndFacilityId(programId, facilityId, pageable); + profiler.start("CARDS_TO_DTO"); List cardDtos = cardsToDtos(pageOfCards.getContent()); return new PageImpl<>(cardDtos, pageable, pageOfCards.getTotalElements()); } @@ -237,30 +251,47 @@ public List createDummyStockCards(UUID programId, UUID facilityId) stockCardRepository.getIdentitiesBy(programId, facilityId); LOGGER.info("Calling ref data to get all approved orderables"); - Map orderableLotsMap = createOrderableLots( + Map orderableLotMap = createOrderableLotMap( orderableReferenceDataService.findAll()); //create dummy(fake/not persisted) cards for approved orderables that don't have cards yet - List dummyCards = createDummyCards(programId, facilityId, orderableLotsMap.values(), + List dummyCards = createDummyCards(programId, facilityId, + orderableLotMap.values(), existingCardIdentities).collect(toList()); - return assignOrderableLotRemoveLineItems(createDtos(dummyCards), orderableLotsMap); + return loadOrderableLotUnitAndRemoveLineItems(createDtos(dummyCards), orderableLotMap); } private List cardsToDtos(List cards) { LOGGER.info("Calling ref data to get all approved orderables"); - Map orderableLotsMap = createOrderableLots( - orderableReferenceDataService.findAll()); - - return assignOrderableLotRemoveLineItems(createDtos(cards), orderableLotsMap); + final Set orderableLotsMapIds = cards.stream().map( + stockCard -> new OrderableLotIdentity(stockCard.getOrderableId(), stockCard.getLotId())) + .collect(Collectors.toSet()); + + final Map orderables = orderableReferenceDataService.findByIds( + orderableLotsMapIds.stream().map(OrderableLotIdentity::getOrderableId).collect(toSet())) + .stream().collect(toMap(OrderableDto::getId, identity())); + final Map lots = lotReferenceDataService.findByIds( + orderableLotsMapIds.stream().map(OrderableLotIdentity::getLotId).filter(Objects::nonNull) + .collect(toSet())).stream().collect(toMap(LotDto::getId, identity())); + + return createDtos(cards).stream().map(cardDto -> { + cardDto.setOrderable(orderables.get(cardDto.getOrderableId())); + cardDto.setLot(cardDto.getLotId() != null ? lots.get(cardDto.getLotId()) : null); + cardDto.setLineItems(null); + return cardDto; + }).collect(Collectors.toList()); } - private List assignOrderableLotRemoveLineItems( + private List loadOrderableLotUnitAndRemoveLineItems( List stockCardDtos, - Map orderableLotsMap) { + Map orderableLotMap) { stockCardDtos.forEach(stockCardDto -> { - OrderableLot orderableLot = orderableLotsMap.get(identityOf(stockCardDto)); - stockCardDto.setOrderable(orderableLot.getOrderable()); - stockCardDto.setLot(orderableLot.getLot()); + OrderableLot orderableLot = + orderableLotMap.get(OrderableLotIdentity.identityOf(stockCardDto)); + if (orderableLot != null) { + stockCardDto.setOrderable(orderableLot.getOrderable()); + stockCardDto.setLot(orderableLot.getLot()); + } stockCardDto.setLineItems(null);//line items are not needed in summary }); return stockCardDtos; @@ -274,7 +305,7 @@ private Stream createDummyCards(UUID programId, UUID facilityId, .map(orderableLot -> StockCard.builder() .programId(programId) .facilityId(facilityId) - .orderableId(orderableLot.getOrderable().getId()) + .orderableId(orderableLot.getOrderableId()) .lotId(orderableLot.getLotId()) .lineItems(emptyList())//dummy cards don't have line items .build()); @@ -282,15 +313,16 @@ private Stream createDummyCards(UUID programId, UUID facilityId, private List filterOrderableLotsWithoutCards( Collection orderableLots, List cardIdentities) { - return orderableLots.stream() - .filter(orderableLot -> cardIdentities.stream() - .noneMatch(cardIdentity -> cardIdentity.equals(identityOf(orderableLot)))) - .collect(toList()); + return orderableLots.stream().filter(orderableLot -> cardIdentities.stream().noneMatch( + cardIdentity -> OrderableLotIdentity.identityOf(orderableLot) + .equals(cardIdentity))).collect(toList()); } - private Map createOrderableLots( + private Map createOrderableLotMap( List orderableDtos) { - Stream orderableLots = orderableDtos.stream().flatMap(this::lotsOfOrderable); + Stream orderableLots = orderableDtos + .stream() + .flatMap(this::lotsOfOrderable); Stream orderablesOnly = orderableDtos.stream() .map(orderableDto -> new OrderableLot(orderableDto, null)); @@ -357,23 +389,18 @@ private ImmutablePair assignOrderableToStockCard( new StockCardAggregate(stockCards, calculatedStockOnHands)); } + @AllArgsConstructor @Getter private static class OrderableLot implements IdentifiableByOrderableLot { private OrderableDto orderable; private LotDto lot; - OrderableLot(OrderableDto orderable, LotDto lot) { - this.orderable = orderable; - this.lot = lot; - } - public UUID getLotId() { return lot == null ? null : lot.getId(); } public UUID getOrderableId() { - return orderable.getId(); + return orderable == null ? null : orderable.getId(); } } - } diff --git a/src/main/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataService.java b/src/main/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataService.java index 939c9e1b..44d314a4 100644 --- a/src/main/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataService.java +++ b/src/main/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataService.java @@ -16,11 +16,15 @@ package org.openlmis.stockmanagement.service.referencedata; import java.time.LocalDate; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.UUID; import org.openlmis.stockmanagement.dto.referencedata.LotDto; +import org.openlmis.stockmanagement.util.RequestParameters; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; @Service public class LotReferenceDataService extends BaseReferenceDataService { @@ -98,4 +102,16 @@ private List getAllLotsBetween(UUID tradeItemId, LocalDate expirationDat return getPage(params).getContent(); } + + /** + * Find Lot by IDs. + * + * @param ids the ids, not null + * @return the list of lots, never null + */ + public List findByIds(Collection ids) { + return CollectionUtils.isEmpty(ids) + ? Collections.emptyList() + : getPage(RequestParameters.init().set("id", ids)).getContent(); + } } diff --git a/src/main/java/org/openlmis/stockmanagement/web/StockCardsController.java b/src/main/java/org/openlmis/stockmanagement/web/StockCardsController.java index 5e4931c6..1530a0f7 100644 --- a/src/main/java/org/openlmis/stockmanagement/web/StockCardsController.java +++ b/src/main/java/org/openlmis/stockmanagement/web/StockCardsController.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.UUID; - import org.openlmis.stockmanagement.dto.StockCardDto; import org.openlmis.stockmanagement.service.PermissionService; import org.openlmis.stockmanagement.service.StockCardService; @@ -28,6 +27,7 @@ import org.openlmis.stockmanagement.util.UuidUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.profiler.Profiler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -100,9 +100,18 @@ public Page getStockCardSummaries( @RequestParam() UUID facility, Pageable pageable ) { - LOGGER.debug("Try to find stock card summaries"); + Profiler profiler = new Profiler("GET_STOCK_CARDS_SUMMARIES"); + profiler.setLogger(LOGGER); + profiler.start("CAN_VIEW_STOCK_CARD"); permissionService.canViewStockCard(program, facility); - return stockCardSummariesService.findStockCards(program, facility, pageable); + profiler.start("FIND_STOCK_CARDS"); + try { + return stockCardSummariesService + .findStockCards(program, facility, pageable, + profiler.startNested("FIND_STOCK_CARDS")); + } finally { + profiler.stop().log(); + } } /** diff --git a/src/test/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionServiceTest.java b/src/test/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionServiceTest.java index 2426ff60..05ca0612 100644 --- a/src/test/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionServiceTest.java +++ b/src/test/java/org/openlmis/stockmanagement/service/HomeFacilityPermissionServiceTest.java @@ -16,8 +16,14 @@ package org.openlmis.stockmanagement.service; import static java.util.UUID.randomUUID; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import static org.openlmis.stockmanagement.service.HomeFacilityPermissionService.WS_TYPE_CODE; import java.util.Collections; import java.util.UUID; @@ -28,6 +34,7 @@ import org.mockito.Mock; import org.openlmis.stockmanagement.dto.referencedata.FacilityDto; import org.openlmis.stockmanagement.dto.referencedata.FacilityTypeDto; +import org.openlmis.stockmanagement.dto.referencedata.GeographicZoneDto; import org.openlmis.stockmanagement.dto.referencedata.SupportedProgramDto; import org.openlmis.stockmanagement.dto.referencedata.UserDto; import org.openlmis.stockmanagement.exception.PermissionMessageException; @@ -46,6 +53,8 @@ @PowerMockIgnore("javax.security.auth.*") public class HomeFacilityPermissionServiceTest { + private static final String OTHER_TYPE_CODE = "otherTypeCode"; + @InjectMocks private HomeFacilityPermissionService homeFacilityPermissionService; @@ -57,10 +66,10 @@ public class HomeFacilityPermissionServiceTest { @Mock private OAuth2Authentication authentication; - + @Mock private FacilityReferenceDataService facilityService; - + private UUID homeFacilityId; private UUID programId; private UUID facilityTypeId; @@ -91,13 +100,78 @@ public void shouldPassValidationIfProgramIsSupported() throws Exception { homeFacilityPermissionService.checkProgramSupported(programId); } - + + @Test + public void shouldPassCheckIfFacilityIsWithinTheSameGeographicZoneAsHomeFacility() { + //given + FacilityDto facilityDto = mock(FacilityDto.class); + FacilityTypeDto facilityTypeDto = new FacilityTypeDto(); + facilityTypeDto.setCode(WS_TYPE_CODE); + when(facilityDto.getType()).thenReturn(facilityTypeDto); + UUID geographicZoneId = randomUUID(); + + mockGeographicZoneId(facilityDto, geographicZoneId); + mockGeographicZoneId(homeFacilityDto, geographicZoneId); + UUID facilityId = UUID.randomUUID(); + when(facilityService.findOne(facilityId)).thenReturn(facilityDto); + + //when + boolean result = homeFacilityPermissionService.checkFacilityAndHomeFacilityLinkage(facilityId); + + //then + assertTrue(result); + verify(facilityService).findOne(facilityId); + verify(facilityService).findOne(homeFacilityId); + } + + @Test + public void shouldFailCheckIfFacilityHasOtherTypeCodeThanWs() { + //given + FacilityDto facilityDto = mock(FacilityDto.class); + FacilityTypeDto facilityTypeDto = new FacilityTypeDto(); + facilityTypeDto.setCode(OTHER_TYPE_CODE); + when(facilityDto.getType()).thenReturn(facilityTypeDto); + UUID geographicZoneId = randomUUID(); + + mockGeographicZoneId(facilityDto, geographicZoneId); + mockGeographicZoneId(homeFacilityDto, geographicZoneId); + UUID facilityId = UUID.randomUUID(); + when(facilityService.findOne(facilityId)).thenReturn(facilityDto); + + //when + boolean result = homeFacilityPermissionService.checkFacilityAndHomeFacilityLinkage(facilityId); + + //then + assertFalse(result); + verify(facilityService).findOne(facilityId); + verify(facilityService, times(0)).findOne(homeFacilityId); + } + + @Test + public void shouldFailCheckIfFacilityIdIsEqualToHomeFacilityId() { + //given + + //when + boolean result = + homeFacilityPermissionService.checkFacilityAndHomeFacilityLinkage(homeFacilityId); + + //then + assertFalse(result); + verifyNoInteractions(facilityService); + } + + private void mockGeographicZoneId(FacilityDto facilityDto, UUID geographicZoneId) { + GeographicZoneDto geographicZoneDto = new GeographicZoneDto(); + geographicZoneDto.setId(geographicZoneId); + when(facilityDto.getGeographicZone()).thenReturn(geographicZoneDto); + } + private void mockUserDto() { userDto = mock(UserDto.class); when(userDto.getHomeFacilityId()).thenReturn(homeFacilityId); when(authenticationHelper.getCurrentUser()).thenReturn(userDto); } - + private void mockFacilityDto() { homeFacilityDto = mock(FacilityDto.class); @@ -112,4 +186,4 @@ private void mockFacilityDto() { when(facilityService.findOne(homeFacilityId)).thenReturn(homeFacilityDto); } -} \ No newline at end of file +} diff --git a/src/test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceTest.java b/src/test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceTest.java index 8b8569b2..08403bb8 100644 --- a/src/test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceTest.java +++ b/src/test/java/org/openlmis/stockmanagement/service/StockCardSummariesServiceTest.java @@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; @@ -30,18 +31,21 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableSet; import java.time.LocalDate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; - +import java.util.stream.Collectors; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -74,57 +78,54 @@ import org.openlmis.stockmanagement.testutils.StockEventDataBuilder; import org.openlmis.stockmanagement.util.Message; import org.openlmis.stockmanagement.util.RequestParameters; +import org.slf4j.profiler.Profiler; +import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +@SuppressWarnings("PMD.TooManyMethods") @RunWith(MockitoJUnitRunner.class) public class StockCardSummariesServiceTest { + private final UUID facilityId = randomUUID(); + private final UUID programId = randomUUID(); + private final UUID orderableId1 = randomUUID(); + private final UUID orderableId2 = randomUUID(); + private final UUID orderableId3 = randomUUID(); + private final UUID orderableId4 = randomUUID(); + private final UUID orderableId5 = randomUUID(); + private final UUID orderableId6 = randomUUID(); + private final UUID orderableId7 = randomUUID(); + private final UUID lotId1 = randomUUID(); + private final UUID lotId2 = randomUUID(); + @Mock private ApprovedProductReferenceDataService approvedProductReferenceDataService; - @Mock private OrderableFulfillReferenceDataService orderableFulfillReferenceDataService; - @Mock private OrderableReferenceDataService orderableReferenceDataService; - @Mock @SuppressWarnings("PMD") private FacilityReferenceDataService facilityRefDataService; - @Mock @SuppressWarnings("PMD") private ProgramReferenceDataService programRefDataService; - @Mock private LotReferenceDataService lotReferenceDataService; - @Mock private CalculatedStockOnHandService calculatedStockOnHandService; - @Mock private StockCardRepository cardRepository; - @Mock private PermissionService permissionService; - @Mock private CalculatedStockOnHandRepository calculatedStockOnHandRepository; - + @Mock + private HomeFacilityPermissionService homeFacilityPermissionService; @InjectMocks private StockCardSummariesService stockCardSummariesService; - private final UUID facilityId = randomUUID(); - private final UUID programId = randomUUID(); - - private final UUID orderableId1 = randomUUID(); - private final UUID orderableId2 = randomUUID(); - private final UUID orderableId3 = randomUUID(); - private final UUID orderableId4 = randomUUID(); - private final UUID orderableId5 = randomUUID(); - private final UUID orderableId6 = randomUUID(); - private final UUID orderableId7 = randomUUID(); - @Test public void shouldCreateDummyCards() { //given @@ -208,9 +209,9 @@ public void shouldFindStockCards() { OrderableDto orderable3 = new OrderableDtoDataBuilder().build(); OrderablesAggregator orderablesAggregator = new OrderablesAggregator(asList( - new ApprovedProductDto(orderable), - new ApprovedProductDto(orderable2), - new ApprovedProductDto(orderable3) + new ApprovedProductDto(orderable), + new ApprovedProductDto(orderable2), + new ApprovedProductDto(orderable3) )); StockCardSummariesV2SearchParams params = new StockCardSummariesV2SearchParamsDataBuilder() @@ -243,18 +244,21 @@ public void shouldFindStockCards() { when(orderableReferenceDataService.getPage(any(RequestParameters.class))) .thenReturn(new PageImpl<>(Collections.emptyList())); + when(homeFacilityPermissionService.checkFacilityAndHomeFacilityLinkage(any(UUID.class))) + .thenReturn(false); + StockEvent event = new StockEventDataBuilder() .withFacility(params.getFacilityId()) .withProgram(params.getProgramId()) .build(); StockCard stockCard = new StockCardDataBuilder(event) - .withOrderable(orderable.getId()) + .withOrderableId(orderable.getId()) .withStockOnHand(12) .build(); StockCard stockCard1 = new StockCardDataBuilder(event) - .withOrderable(orderable3.getId()) + .withOrderableId(orderable3.getId()) .withStockOnHand(26) .build(); @@ -275,6 +279,9 @@ public void shouldThrowExceptionIfNoPermission() { StockCardSummariesV2SearchParams params = new StockCardSummariesV2SearchParamsDataBuilder().build(); + when(homeFacilityPermissionService.checkFacilityAndHomeFacilityLinkage(any(UUID.class))) + .thenReturn(false); + doThrow(new PermissionMessageException(new Message("no permission"))) .when(permissionService) @@ -297,7 +304,7 @@ public void shouldAggregateStockCardsByCommodityTypes() { when(orderableFulfillReferenceDataService .findByIds( ImmutableSet.of(orderableId2, orderableId3, - orderableId5, orderableId6, orderableId7))) + orderableId5, orderableId6, orderableId7))) .thenReturn(fulfillMap); StockEvent event = new StockEventDataBuilder() @@ -306,27 +313,27 @@ public void shouldAggregateStockCardsByCommodityTypes() { .build(); StockCard stockCard1 = new StockCardDataBuilder(event) - .withOrderable(orderableId2) + .withOrderableId(orderableId2) .withStockOnHand(12) .build(); StockCard stockCard2 = new StockCardDataBuilder(event) - .withOrderable(orderableId3) + .withOrderableId(orderableId3) .withStockOnHand(26) .build(); StockCard stockCard3 = new StockCardDataBuilder(event) - .withOrderable(orderableId5) + .withOrderableId(orderableId5) .withStockOnHand(36) .build(); StockCard stockCard4 = new StockCardDataBuilder(event) - .withOrderable(orderableId6) + .withOrderableId(orderableId6) .withStockOnHand(46) .build(); StockCard stockCard5 = new StockCardDataBuilder(event) - .withOrderable(orderableId7) + .withOrderableId(orderableId7) .withStockOnHand(56) .build(); @@ -354,7 +361,8 @@ public void shouldAggregateStockCardsByCommodityTypes() { Map cardMap = stockCardSummariesService.getGroupedStockCards(programId, facilityId, null, - LocalDate.of(2017, 3, 16), LocalDate.of(2017, 3, 19)); + LocalDate.of(2017, 3, 16), + LocalDate.of(2017, 3, 19)); assertThat(cardMap.keySet(), hasItems(orderableId1, orderableId4, orderableId6, orderableId7)); @@ -390,7 +398,7 @@ public void shouldAggregateStockCardsByCommodityTypesWhenNoStartDateProvided() { when(orderableFulfillReferenceDataService .findByIds( ImmutableSet.of(orderableId2, orderableId3, orderableId5, - orderableId6, orderableId7))) + orderableId6, orderableId7))) .thenReturn(fulfillMap); StockEvent event = new StockEventDataBuilder() @@ -399,27 +407,27 @@ public void shouldAggregateStockCardsByCommodityTypesWhenNoStartDateProvided() { .build(); StockCard stockCard1 = new StockCardDataBuilder(event) - .withOrderable(orderableId2) + .withOrderableId(orderableId2) .withStockOnHand(12) .build(); StockCard stockCard2 = new StockCardDataBuilder(event) - .withOrderable(orderableId3) + .withOrderableId(orderableId3) .withStockOnHand(26) .build(); StockCard stockCard3 = new StockCardDataBuilder(event) - .withOrderable(orderableId5) + .withOrderableId(orderableId5) .withStockOnHand(36) .build(); StockCard stockCard4 = new StockCardDataBuilder(event) - .withOrderable(orderableId6) + .withOrderableId(orderableId6) .withStockOnHand(46) .build(); StockCard stockCard5 = new StockCardDataBuilder(event) - .withOrderable(orderableId7) + .withOrderableId(orderableId7) .withStockOnHand(56) .build(); @@ -436,15 +444,15 @@ public void shouldAggregateStockCardsByCommodityTypesWhenNoStartDateProvided() { .thenReturn(calculatedStockOnHands); final CalculatedStockOnHand calculatedStockOnHand1 = - generateCalculatedStockOnHandWithEndDate(stockCard1); + generateCalculatedStockOnHandWithEndDate(stockCard1); final CalculatedStockOnHand calculatedStockOnHand2 = - generateCalculatedStockOnHandWithEndDate(stockCard2); + generateCalculatedStockOnHandWithEndDate(stockCard2); final CalculatedStockOnHand calculatedStockOnHand3 = - generateCalculatedStockOnHandWithEndDate(stockCard3); + generateCalculatedStockOnHandWithEndDate(stockCard3); final CalculatedStockOnHand calculatedStockOnHand4 = - generateCalculatedStockOnHandWithEndDate(stockCard4); + generateCalculatedStockOnHandWithEndDate(stockCard4); final CalculatedStockOnHand calculatedStockOnHand5 = - generateCalculatedStockOnHandWithEndDate(stockCard5); + generateCalculatedStockOnHandWithEndDate(stockCard5); Map cardMap = stockCardSummariesService.getGroupedStockCards(programId, facilityId, null, @@ -470,6 +478,93 @@ public void shouldAggregateStockCardsByCommodityTypesWhenNoStartDateProvided() { hasItems(calculatedStockOnHand, calculatedStockOnHand5)); } + @Test + public void shouldFindStockCardsForProgramAndFacilityIds() { + //given + prepareForFindStockCards(null); + + //when + List stockCardsDtos = + stockCardSummariesService.findStockCards(programId, facilityId); + + //then + assertThat(stockCardsDtos, hasSize(2)); + checkStockCardDto(stockCardsDtos, orderableId1, lotId1); + checkStockCardDto(stockCardsDtos, orderableId2, lotId2); + } + + @Test + public void shouldFindStockCardsForProgramAndFacilityIdsAndPageableAndProfiler() { + //given + Pageable pageable = mock(Pageable.class); + Profiler profiler = mock(Profiler.class); + prepareForFindStockCards(pageable); + + //when + Page stockCardsPage = + stockCardSummariesService.findStockCards(programId, facilityId, pageable, profiler); + + //then + assertEquals(2L, stockCardsPage.getTotalElements()); + List stockCardDtos = stockCardsPage.get().collect(Collectors.toList()); + checkStockCardDto(stockCardDtos, orderableId1, lotId1); + checkStockCardDto(stockCardDtos, orderableId2, lotId2); + } + + private void prepareForFindStockCards(Pageable pageable) { + OrderableDto orderable1 = createOrderableDto(orderableId1, "1"); + OrderableDto orderable2 = createOrderableDto(orderableId2, "2"); + + LotDto lot1 = LotDto.builder().id(lotId1).build(); + LotDto lot2 = LotDto.builder().id(lotId2).build(); + + StockEvent event = new StockEventDataBuilder() + .withFacility(facilityId) + .withProgram(programId) + .build(); + + StockCard stockCard1 = new StockCardDataBuilder(event) + .withOrderableId(orderableId1) + .withStockOnHand(12) + .withLotId(lotId1) + .build(); + + StockCard stockCard2 = new StockCardDataBuilder(event) + .withOrderableId(orderableId2) + .withStockOnHand(26) + .withLotId(lotId2) + .build(); + + List stockCards = asList(stockCard1, stockCard2); + + if (pageable != null) { + Page stockCardPage = new PageImpl<>(stockCards, pageable, stockCards.size()); + when(cardRepository.findByProgramIdAndFacilityId(programId, facilityId, pageable)) + .thenReturn(stockCardPage); + } else { + when(cardRepository.findByProgramIdAndFacilityId(programId, facilityId)) + .thenReturn(stockCards); + } + + when(orderableReferenceDataService + .findByIds(new HashSet<>(Arrays.asList(orderableId1, orderableId2)))) + .thenReturn(Arrays.asList(orderable1, orderable2)); + when(lotReferenceDataService.findByIds(new HashSet<>(Arrays.asList(lotId1, lotId2)))) + .thenReturn(Arrays.asList(lot1, lot2)); + } + + private void checkStockCardDto( + List stockCardsDtos, + UUID orderableId, + UUID lotId) { + Optional stockCardDtoOptional = stockCardsDtos.stream() + .filter(stockCardDto -> stockCardDto.getOrderableId().equals(orderableId)) + .findFirst(); + assertThat(stockCardDtoOptional.isPresent(), is(true)); + StockCardDto stockCardDto = stockCardDtoOptional.get(); + assertThat(stockCardDto.getLotId(), is(lotId)); + } + private OrderableDto createOrderableDto(UUID orderableId, String productName) { return OrderableDto.builder() .id(orderableId) @@ -490,9 +585,9 @@ private CalculatedStockOnHand generateAndMockCalculatedStockOnHand(StockCard sto private CalculatedStockOnHand generateCalculatedStockOnHandWithEndDate(StockCard stockCard) { CalculatedStockOnHand calculatedStockOnHand = new CalculatedStockOnHandDataBuilder().build(); when(calculatedStockOnHandRepository - .findFirstByStockCardIdAndOccurredDateLessThanEqualOrderByOccurredDateDesc( - stockCard.getId(), LocalDate.of(2017, 3, 19))) - .thenReturn(Optional.ofNullable(calculatedStockOnHand)); + .findFirstByStockCardIdAndOccurredDateLessThanEqualOrderByOccurredDateDesc( + stockCard.getId(), LocalDate.of(2017, 3, 19))) + .thenReturn(Optional.ofNullable(calculatedStockOnHand)); return calculatedStockOnHand; } diff --git a/src/test/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataServiceTest.java b/src/test/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataServiceTest.java index 5b9be24b..a5709dc0 100644 --- a/src/test/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataServiceTest.java +++ b/src/test/java/org/openlmis/stockmanagement/service/referencedata/LotReferenceDataServiceTest.java @@ -15,6 +15,7 @@ package org.openlmis.stockmanagement.service.referencedata; +import static java.util.Collections.singletonList; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; import static org.junit.Assert.assertEquals; @@ -100,4 +101,25 @@ public void getAllLotsExpiringOnDateShouldReturnMatchingLots() { assertAuthHeader(entityCaptor.getValue()); assertNull(entityCaptor.getValue().getBody()); } + + @Test + public void findByIdsShouldReturnMatchingLots() { + LotDto lot = mockPageResponseEntityAndGetDto(); + + List response = service.findByIds(singletonList(lot.getId())); + + assertThat(response, hasSize(1)); + assertThat(response, hasItem(lot)); + + verify(restTemplate).exchange( + uriCaptor.capture(), eq(HttpMethod.GET), entityCaptor.capture(), + refEq(new DynamicPageTypeReference<>(LotDto.class))); + + URI uri = uriCaptor.getValue(); + assertEquals(serviceUrl + service.getUrl() + "?id=" + lot.getId().toString(), + uri.toString()); + + assertAuthHeader(entityCaptor.getValue()); + assertNull(entityCaptor.getValue().getBody()); + } } diff --git a/src/test/java/org/openlmis/stockmanagement/testutils/StockCardDataBuilder.java b/src/test/java/org/openlmis/stockmanagement/testutils/StockCardDataBuilder.java index 101dd894..b1847e38 100644 --- a/src/test/java/org/openlmis/stockmanagement/testutils/StockCardDataBuilder.java +++ b/src/test/java/org/openlmis/stockmanagement/testutils/StockCardDataBuilder.java @@ -50,12 +50,12 @@ public StockCardDataBuilder withoutId() { return this; } - public StockCardDataBuilder withOrderable(UUID orderable) { + public StockCardDataBuilder withOrderableId(UUID orderable) { orderableId = orderable; return this; } - public StockCardDataBuilder withLot(UUID lot) { + public StockCardDataBuilder withLotId(UUID lot) { lotId = lot; return this; } @@ -92,7 +92,7 @@ public StockCard buildWithStockOnHandAndLineItemAndOrderableId(Integer stockOnHa StockCardLineItem lineItem, UUID orderableId) { return this - .withOrderable(orderableId) + .withOrderableId(orderableId) .withStockOnHand(stockOnHand) .withLineItem(lineItem) .build(); diff --git a/src/test/java/org/openlmis/stockmanagement/web/stockcardsummariesv2/StockCardSummariesV2DtoBuilderTest.java b/src/test/java/org/openlmis/stockmanagement/web/stockcardsummariesv2/StockCardSummariesV2DtoBuilderTest.java index 8a9581ad..8d0ac0dc 100644 --- a/src/test/java/org/openlmis/stockmanagement/web/stockcardsummariesv2/StockCardSummariesV2DtoBuilderTest.java +++ b/src/test/java/org/openlmis/stockmanagement/web/stockcardsummariesv2/StockCardSummariesV2DtoBuilderTest.java @@ -89,7 +89,7 @@ public void before() { new StockCardLineItemDataBuilder().buildWithStockOnHand(30), orderable3.getId()); stockCard3b = new StockCardDataBuilder(event) - .withLot(UUID.randomUUID()) + .withLotId(UUID.randomUUID()) .buildWithStockOnHandAndLineItemAndOrderableId(10, new StockCardLineItemDataBuilder().buildWithStockOnHand(10), orderable3.getId());