From 1aa4414a1f610cc10afd5684b20f681279420777 Mon Sep 17 00:00:00 2001 From: Adam Nawrot <113436691+anawrotsoldevelo@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:14:07 +0100 Subject: [PATCH] OLMIS-7793: Changed AMC calculation for SM facilities (#93) * OLMIS-7793: Test checking AMC for submitting requisition in SM * OLMIS-7793: Fixed AMC calculation for submit * OLMIS-7793: Adjusted tests to match changed submit method * OLMIS-7793: Changed AMC calculation for authorize, approve and reject * OLMIS-7793: Adjusted comments and formatting * OLMIS-7793: Changed calculate stock fields methods to SM * OLMIS-7793: Initial requisition refactor * OLMIS-7793: Adjusted tests after code refactor * OLMIS-7793: Fixed a bug in calculations * OLMIS-7793: Removed no longer valid code * OLMIS-7793: Changed stockCardRangeSummaryForAverage fetching behaviour for a single period * OLMIS-7793: Code adjustments after a review --- .../RequisitionRepositoryIntegrationTest.java | 54 +++-- .../RequisitionControllerIntegrationTest.java | 142 +++++++++---- .../domain/requisition/Requisition.java | 162 ++++++++++++-- .../requisition/RequisitionLineItem.java | 32 ++- .../repository/RequisitionRepository.java | 4 +- .../requisition/service/PeriodService.java | 12 +- .../service/RequisitionService.java | 62 +++++- .../PeriodReferenceDataService.java | 14 ++ .../web/BaseRequisitionController.java | 10 +- .../web/RequisitionController.java | 9 +- .../web/RequisitionV2Controller.java | 7 +- .../requisition/RequisitionDataBuilder.java | 5 + .../requisition/RequisitionLineItemTest.java | 3 + .../domain/requisition/RequisitionTest.java | 200 ++++++++++++------ .../service/RequisitionServiceTest.java | 35 ++- .../StockCardRangeSummaryDtoDataBuilder.java | 5 + .../RequisitionValidationTestUtils.java | 4 + .../web/RequisitionControllerTest.java | 162 ++++++++------ 18 files changed, 696 insertions(+), 226 deletions(-) diff --git a/src/integration-test/java/org/openlmis/requisition/repository/RequisitionRepositoryIntegrationTest.java b/src/integration-test/java/org/openlmis/requisition/repository/RequisitionRepositoryIntegrationTest.java index 6abeab7f4..8a9d5bca4 100644 --- a/src/integration-test/java/org/openlmis/requisition/repository/RequisitionRepositoryIntegrationTest.java +++ b/src/integration-test/java/org/openlmis/requisition/repository/RequisitionRepositoryIntegrationTest.java @@ -71,13 +71,18 @@ import org.openlmis.requisition.domain.requisition.StockAdjustment; import org.openlmis.requisition.domain.requisition.StockAdjustmentDataBuilder; import org.openlmis.requisition.dto.OrderableDto; +import org.openlmis.requisition.dto.ProcessingPeriodDto; import org.openlmis.requisition.dto.VersionIdentityDto; import org.openlmis.requisition.repository.custom.DefaultRequisitionSearchParams; import org.openlmis.requisition.repository.custom.RequisitionSearchParams; +import org.openlmis.requisition.service.PeriodService; +import org.openlmis.requisition.service.RequisitionService; import org.openlmis.requisition.testutils.AvailableRequisitionColumnDataBuilder; import org.openlmis.requisition.testutils.DefaultRequisitionSearchParamsDataBuilder; +import org.openlmis.requisition.testutils.ProcessingPeriodDtoDataBuilder; import org.openlmis.requisition.testutils.StatusChangeDataBuilder; import org.openlmis.requisition.utils.Pagination; +import org.slf4j.profiler.Profiler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -94,9 +99,18 @@ public class RequisitionRepositoryIntegrationTest private Pageable pageRequest = PageRequest.of( Pagination.DEFAULT_PAGE_NUMBER, Pagination.NO_PAGINATION); + private Profiler profiler; + @Autowired private AvailableRequisitionColumnRepository availableRequisitionColumnRepository; + @Autowired + private RequisitionService requisitionService; + + @Autowired + private PeriodService periodService; + + @Before public void setUp() { testTemplate = templateRepository.save(new RequisitionTemplateDataBuilder().build()); @@ -104,6 +118,7 @@ public void setUp() { for (int count = 0; count < 5; ++count) { requisitions.add(repository.save(generateInstance())); } + profiler = new Profiler("TEST_PROFILER"); } @Test @@ -766,6 +781,9 @@ private void searchByProgramSupervisoryNodePairsShouldSortByAuthorizedDate(Direc final UUID user = UUID.randomUUID(); final Map products = emptyMap(); + final ProcessingPeriodDto period = new ProcessingPeriodDtoDataBuilder() + .buildAsDto(); + Requisition matchingRequisition1 = requisitions.get(0); matchingRequisition1.setProgramId(programId); matchingRequisition1.setSupervisoryNodeId(supervisoryNodeId); @@ -790,41 +808,53 @@ private void searchByProgramSupervisoryNodePairsShouldSortByAuthorizedDate(Direc // to verify that the latest authorized status change is used for comparison // 2) we have to save requisitions after each status change because the createdDate field // is set by hibernate - because of @PrePersist annotation in the BaseTimestampedEntity - matchingRequisition1.submit(products, user, false); + matchingRequisition1.submit( + products, user, false, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition1); - matchingRequisition2.submit(products, user, false); + matchingRequisition2.submit( + products, user, false, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition2); - matchingRequisition3.submit(products, user, false); + matchingRequisition3.submit( + products, user, false, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition3); - matchingRequisition1.authorize(products, user); + matchingRequisition1.authorize( + products, user, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition1); - matchingRequisition2.authorize(products, user); + matchingRequisition2.authorize( + products, user, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition2); - matchingRequisition3.authorize(products, user); + matchingRequisition3.authorize( + products, user, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition3); - matchingRequisition2.reject(products, user); + matchingRequisition2.reject( + products, user, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition2); - matchingRequisition3.reject(products, user); + matchingRequisition3.reject( + products, user, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition3); - matchingRequisition3.submit(products, user, false); + matchingRequisition3.submit( + products, user, false, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition3); - matchingRequisition2.submit(products, user, false); + matchingRequisition2.submit( + products, user, false, period, requisitionService, periodService, profiler); saveAndFlushWithDelay(matchingRequisition2); - matchingRequisition3.authorize(products, user); + matchingRequisition3.authorize( + products, user, period, requisitionService, periodService, profiler); matchingRequisition3.setSupervisoryNodeId(supervisoryNodeId); saveAndFlushWithDelay(matchingRequisition3); - matchingRequisition2.authorize(products, user); + matchingRequisition2.authorize( + products, user, period, requisitionService, periodService, profiler); matchingRequisition2.setSupervisoryNodeId(supervisoryNodeId); saveAndFlushWithDelay(matchingRequisition2); diff --git a/src/integration-test/java/org/openlmis/requisition/web/RequisitionControllerIntegrationTest.java b/src/integration-test/java/org/openlmis/requisition/web/RequisitionControllerIntegrationTest.java index b3b582fb6..f3be6ac36 100644 --- a/src/integration-test/java/org/openlmis/requisition/web/RequisitionControllerIntegrationTest.java +++ b/src/integration-test/java/org/openlmis/requisition/web/RequisitionControllerIntegrationTest.java @@ -104,11 +104,14 @@ import org.openlmis.requisition.repository.custom.RequisitionSearchParams; import org.openlmis.requisition.service.DataRetrievalException; import org.openlmis.requisition.service.PageDto; +import org.openlmis.requisition.service.PeriodService; import org.openlmis.requisition.service.PermissionService; +import org.openlmis.requisition.service.RequisitionService; import org.openlmis.requisition.service.referencedata.ApproveProductsAggregator; import org.openlmis.requisition.testutils.DtoGenerator; import org.openlmis.requisition.testutils.FacilityDtoDataBuilder; import org.openlmis.requisition.testutils.OrderableDtoDataBuilder; +import org.openlmis.requisition.testutils.ProcessingPeriodDtoDataBuilder; import org.openlmis.requisition.testutils.ProgramDtoDataBuilder; import org.openlmis.requisition.testutils.ReleasableRequisitionDtoDataBuilder; import org.openlmis.requisition.testutils.UserDtoDataBuilder; @@ -117,6 +120,7 @@ import org.openlmis.requisition.utils.Pagination; import org.postgresql.util.PSQLException; import org.postgresql.util.ServerErrorMessage; +import org.slf4j.profiler.Profiler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -503,7 +507,9 @@ public void shouldSubmitValidRequisition() { // given Requisition requisition = spyRequisitionAndStubRepository(RequisitionStatus.INITIATED); - doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean()); + doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); doReturn(ValidationResult.success()) .when(permissionService).canSubmitRequisition(requisition); doReturn(new ProgramDtoDataBuilder().buildWithNotSkippedAuthorizationStep()) @@ -526,7 +532,9 @@ public void shouldSubmitValidRequisition() { // then assertEquals(requisition.getId(), result.getId()); - verify(requisition, atLeastOnce()).submit(any(), any(UUID.class), anyBoolean()); + verify(requisition, atLeastOnce()).submit(any(), any(UUID.class), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -534,7 +542,9 @@ public void shouldSubmitValidRequisition() { public void shouldSubmitRequisitionWithIdempotencyKey() { Requisition requisition = spyRequisitionAndStubRepository(RequisitionStatus.INITIATED); - doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean()); + doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); doReturn(ValidationResult.success()) .when(permissionService).canSubmitRequisition(requisition); doReturn(new ProgramDtoDataBuilder().buildWithNotSkippedAuthorizationStep()) @@ -560,7 +570,9 @@ public void shouldSubmitRequisitionWithIdempotencyKey() { verify(processedRequestsRedisRepository, times(1)).addOrUpdate(key, requisition.getId()); assertEquals(requisition.getId(), result.getId()); - verify(requisition, atLeastOnce()).submit(any(), any(UUID.class), anyBoolean()); + verify(requisition, atLeastOnce()).submit(any(), any(UUID.class), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -568,7 +580,9 @@ public void shouldSubmitRequisitionWithIdempotencyKey() { public void shouldNotSubmitRequisitionWithUsedIdempotencyKey() { Requisition requisition = spyRequisitionAndStubRepository(RequisitionStatus.INITIATED); - doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean()); + doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); doReturn(ValidationResult.success()) .when(permissionService).canSubmitRequisition(requisition); doReturn(new ProgramDtoDataBuilder().buildWithNotSkippedAuthorizationStep()) @@ -597,7 +611,9 @@ public void shouldNotSubmitRequisitionWithUsedIdempotencyKey() { public void shouldNotSubmitRequisitionWithIdempotencyKeyInWrongFormat() { Requisition requisition = spyRequisitionAndStubRepository(RequisitionStatus.INITIATED); - doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean()); + doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); doReturn(ValidationResult.success()) .when(permissionService).canSubmitRequisition(requisition); doReturn(new ProgramDtoDataBuilder().buildWithNotSkippedAuthorizationStep()) @@ -626,7 +642,9 @@ public void shouldNotSubmitWhenPeriodEndDateIsInFuture() { // given Requisition requisition = spyRequisitionAndStubRepository(RequisitionStatus.INITIATED); - doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean()); + doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); doReturn(ValidationResult.success()) .when(permissionService).canSubmitRequisition(requisition); @@ -647,7 +665,9 @@ public void shouldNotSubmitWhenPeriodEndDateIsInFuture() { // then verify(requisition, never()).submit(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid(), anyBoolean()); + anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -673,7 +693,9 @@ public void shouldNotSubmitRequisitionWhenUserHasNoRightForSubmit() { // then verify(requisition, never()).submit(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid(), anyBoolean()); + anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -682,7 +704,9 @@ public void shouldNotAllowForStatusChangeDuplicationOnSubmit() { // given Requisition requisition = spyRequisitionAndStubRepository(RequisitionStatus.INITIATED); - doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean()); + doNothing().when(requisition).submit(any(), anyUuid(), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); doReturn(ValidationResult.success()) .when(permissionService).canSubmitRequisition(requisition); doReturn(new ProgramDtoDataBuilder().buildWithNotSkippedAuthorizationStep()) @@ -903,8 +927,12 @@ public void shouldNotSkipRequisitionIfProgramNotExist() { public void shouldRejectRequisition() { // given Requisition requisition = generateRequisition(RequisitionStatus.AUTHORIZED); - given(requisitionService.reject(requisition, emptyMap(), emptyList())) - .willReturn(requisition); + ProcessingPeriodDto period = new ProcessingPeriodDtoDataBuilder().buildAsDto(); + + given(periodService.getPeriod(requisition.getProcessingPeriodId())).willReturn(period); + given(requisitionService.reject(eq(requisition), eq(emptyMap()), eq(emptyList()), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class))).willReturn(requisition); doReturn(ValidationResult.success()) .when(permissionService).canApproveRequisition(requisition); @@ -920,7 +948,9 @@ public void shouldRejectRequisition() { .statusCode(200); // then - verify(requisitionService, atLeastOnce()).reject(requisition, emptyMap(), emptyList()); + verify(requisitionService, atLeastOnce()).reject(eq(requisition), eq(emptyMap()), + eq(emptyList()), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -928,8 +958,12 @@ public void shouldRejectRequisition() { @Test public void shouldRejectRequisitionWithIdempotencyKey() { Requisition requisition = generateRequisition(RequisitionStatus.AUTHORIZED); - given(requisitionService.reject(requisition, emptyMap(), emptyList())) - .willReturn(requisition); + ProcessingPeriodDto period = new ProcessingPeriodDtoDataBuilder().buildAsDto(); + + given(requisitionService.reject(eq(requisition), eq(emptyMap()), eq(emptyList()), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class))).willReturn(requisition); + given(periodService.getPeriod(requisition.getProcessingPeriodId())).willReturn(period); doReturn(ValidationResult.success()) .when(permissionService).canApproveRequisition(requisition); @@ -954,8 +988,9 @@ public void shouldRejectRequisitionWithIdempotencyKey() { @Test public void shouldNotRejectRequisitionWithUsedIdempotencyKey() { Requisition requisition = generateRequisition(RequisitionStatus.AUTHORIZED); - given(requisitionService.reject(requisition, emptyMap(), emptyList())) - .willReturn(requisition); + given(requisitionService.reject(eq(requisition), eq(emptyMap()), eq(emptyList()), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class))).willReturn(requisition); doReturn(ValidationResult.success()) .when(permissionService).canApproveRequisition(requisition); @@ -979,7 +1014,9 @@ public void shouldNotRejectRequisitionWithUsedIdempotencyKey() { @Test public void shouldNotRejectRequisitionWithIdempotencyKeyInWrongFormat() { Requisition requisition = generateRequisition(RequisitionStatus.AUTHORIZED); - given(requisitionService.reject(requisition, emptyMap(), emptyList())) + given(requisitionService.reject(eq(requisition), eq(emptyMap()), eq(emptyList()), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class))) .willReturn(requisition); doReturn(ValidationResult.success()) .when(permissionService).canApproveRequisition(requisition); @@ -1022,7 +1059,9 @@ public void shouldNotRejectRequisitionWhenUserHasNoRightForApprove() { .body(MESSAGE, equalTo(getMessage(PERMISSION_ERROR_MESSAGE, missingPermission))); // then - verify(requisitionService, never()).reject(requisition, emptyMap(), emptyList()); + verify(requisitionService, never()).reject(eq(requisition), eq(emptyMap()), eq(emptyList()), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -1031,7 +1070,10 @@ public void shouldNotRejectRequisitionWithWrongStatus() { // given Requisition requisition = generateRequisition(RequisitionStatus.AUTHORIZED); UUID requisitionId = requisition.getId(); + ProcessingPeriodDto period = new ProcessingPeriodDtoDataBuilder().buildAsDto(); + given(requisitionRepository.findById(requisitionId)).willReturn(Optional.of(requisition)); + given(periodService.getPeriod(requisition.getProcessingPeriodId())).willReturn(period); doReturn(ValidationResult.success()) .when(permissionService).canApproveRequisition(requisition); @@ -1039,8 +1081,9 @@ public void shouldNotRejectRequisitionWithWrongStatus() { String errorKey = MessageKeys.ERROR_REQUISITION_MUST_BE_WAITING_FOR_APPROVAL; ValidationMessageException exception = mockValidationException(errorKey, requisitionId); - doThrow(exception).when(requisitionService).reject(requisition, emptyMap(), - emptyList()); + doThrow(exception).when(requisitionService).reject(eq(requisition), eq(emptyMap()), + eq(emptyList()), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); // when restAssured.given() @@ -1080,7 +1123,8 @@ public void shouldAuthorizeRequisition() { given(orderableReferenceDataService.findByIdentities(anySetOf(VersionEntityReference.class))) .willReturn(orderables); doNothing().when(requisition).authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid()); + anyUuid(), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); doReturn(ValidationResult.success()).when(permissionService) .canAuthorizeRequisition(requisition); mockValidationSuccess(); @@ -1097,7 +1141,9 @@ public void shouldAuthorizeRequisition() { // then verify(requisition, atLeastOnce()) - .authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), anyUuid()); + .authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); verify(supervisoryNodeReferenceDataService) .findSupervisoryNode(requisition.getProgramId(), requisition.getFacilityId()); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); @@ -1110,7 +1156,8 @@ public void shouldAuthorizeRequisitionWithIdempotencyKey() { given(orderableReferenceDataService.findByIdentities(anySetOf(VersionEntityReference.class))) .willReturn(Collections.emptyList()); doNothing().when(requisition).authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid()); + anyUuid(), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); doReturn(ValidationResult.success()).when(permissionService) .canAuthorizeRequisition(requisition); mockValidationSuccess(); @@ -1130,7 +1177,9 @@ public void shouldAuthorizeRequisitionWithIdempotencyKey() { verify(processedRequestsRedisRepository, times(1)).addOrUpdate(key, requisition.getId()); verify(requisition, atLeastOnce()) - .authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), anyUuid()); + .authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); verify(supervisoryNodeReferenceDataService) .findSupervisoryNode(requisition.getProgramId(), requisition.getFacilityId()); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); @@ -1143,7 +1192,8 @@ public void shouldNotAuthorizeRequisitionWithUsedIdempotencyKey() { given(orderableReferenceDataService.findByIdentities(anySetOf(VersionEntityReference.class))) .willReturn(Collections.emptyList()); doNothing().when(requisition).authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid()); + anyUuid(), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); doReturn(ValidationResult.success()).when(permissionService) .canAuthorizeRequisition(requisition); mockValidationSuccess(); @@ -1170,7 +1220,8 @@ public void shouldNotAuthorizeRequisitionWithIdempotencyKeyInWrongFormat() { given(orderableReferenceDataService.findByIdentities(anySetOf(VersionEntityReference.class))) .willReturn(Collections.emptyList()); doNothing().when(requisition).authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid()); + anyUuid(), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); doReturn(ValidationResult.success()).when(permissionService) .canAuthorizeRequisition(requisition); mockValidationSuccess(); @@ -1196,7 +1247,8 @@ public void shouldNotAuthorizeRequisitionWhenPeriodEndDateIsInFuture() { given(orderableReferenceDataService.findByIdentities(anySetOf(VersionEntityReference.class))) .willReturn(Collections.emptyList()); doNothing().when(requisition).authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid()); + anyUuid(), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); doReturn(ValidationResult.success()).when(permissionService) .canAuthorizeRequisition(requisition); mockValidationSuccess(); @@ -1214,7 +1266,8 @@ public void shouldNotAuthorizeRequisitionWhenPeriodEndDateIsInFuture() { // then verify(requisition, never()).submit(anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyUuid(), anyBoolean()); + anyUuid(), anyBoolean(), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -1240,7 +1293,9 @@ public void shouldNotAuthorizeRequisitionWhenUserHasNoRightForAuthorize() { // then verify(requisition, never()) - .authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), any(UUID.class)); + .authorize(anyMapOf(VersionIdentityDto.class, OrderableDto.class), any(UUID.class), + any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -1572,7 +1627,9 @@ public void shouldApproveRequisitionWithIdempotencyKey() { anyUuid()); doNothing().when(requisition).approve(anyUuid(), anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyCollectionOf(SupplyLineDto.class), anyUuid()); + anyCollectionOf(SupplyLineDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); mockExternalServiceCalls(); mockValidationSuccess(); @@ -1603,7 +1660,9 @@ public void shouldNotApproveRequisitionWithUsedIdempotencyKey() { anyUuid()); doNothing().when(requisition).approve(anyUuid(), anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyCollectionOf(SupplyLineDto.class), anyUuid()); + anyCollectionOf(SupplyLineDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); mockExternalServiceCalls(); mockValidationSuccess(); @@ -1634,7 +1693,9 @@ public void shouldNotApproveRequisitionWithIdempotencyKeyInWrongFormat() { anyUuid()); doNothing().when(requisition).approve(anyUuid(), anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyCollectionOf(SupplyLineDto.class), anyUuid()); + anyCollectionOf(SupplyLineDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); mockExternalServiceCalls(); mockValidationSuccess(); @@ -1663,7 +1724,9 @@ public void shouldNotApproveRequisitionWhenPeriodEndDateIsInFuture() { anyUuid()); doNothing().when(requisition).approve(anyUuid(), anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyCollectionOf(SupplyLineDto.class), anyUuid()); + anyCollectionOf(SupplyLineDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); mockExternalServiceCalls(); mockValidationSuccess(); @@ -1684,7 +1747,8 @@ public void shouldNotApproveRequisitionWhenPeriodEndDateIsInFuture() { // then verify(requisition, never()) .submit(anyMapOf(VersionIdentityDto.class, OrderableDto.class), anyUuid(), - anyBoolean()); + anyBoolean(), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -1711,7 +1775,9 @@ public void shouldNotApproveRequisitionWhenUserHasNoRightForApprove() { // then verify(requisition, never()).approve(anyUuid(), anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyCollectionOf(SupplyLineDto.class), anyUuid()); + anyCollectionOf(SupplyLineDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } @@ -1740,7 +1806,9 @@ public void shouldNotApproveRequisitionWhenUserHasNoRightToApproveForSupervisory // then verify(requisition, never()).approve(anyUuid(), anyMapOf(VersionIdentityDto.class, OrderableDto.class), - anyCollectionOf(SupplyLineDto.class), anyUuid()); + anyCollectionOf(SupplyLineDto.class), anyUuid(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); assertThat(RAML_ASSERT_MESSAGE, restAssured.getLastReport(), RamlMatchers.hasNoViolations()); } diff --git a/src/main/java/org/openlmis/requisition/domain/requisition/Requisition.java b/src/main/java/org/openlmis/requisition/domain/requisition/Requisition.java index b2faff18d..cb712d3f7 100644 --- a/src/main/java/org/openlmis/requisition/domain/requisition/Requisition.java +++ b/src/main/java/org/openlmis/requisition/domain/requisition/Requisition.java @@ -104,7 +104,9 @@ import org.openlmis.requisition.dto.stockmanagement.StockCardRangeSummaryDto; import org.openlmis.requisition.errorhandling.ValidationResult; import org.openlmis.requisition.exception.ValidationMessageException; +import org.openlmis.requisition.service.PeriodService; import org.openlmis.requisition.service.PermissionService; +import org.openlmis.requisition.service.RequisitionService; import org.openlmis.requisition.utils.Message; import org.slf4j.ext.XLogger; import org.slf4j.ext.XLoggerFactory; @@ -390,14 +392,15 @@ public Set getAllApprovedProductIdentities() { * @param products Collection of orderables. */ public void updateFrom(Requisition requisition, Map products, - Map approvedProducts, - boolean isDatePhysicalStockCountCompletedEnabled) { + Map approvedProducts, + boolean isDatePhysicalStockCountCompletedEnabled, + RequisitionService requisitionService, PeriodService periodService) { LOGGER.entry(requisition, products, isDatePhysicalStockCountCompletedEnabled); Profiler profiler = new Profiler("REQUISITION_UPDATE_FROM"); profiler.setLogger(LOGGER); profiler.start("SET_DRAFT_STATUS_MESSAGE"); - this.draftStatusMessage = requisition.draftStatusMessage; + draftStatusMessage = requisition.draftStatusMessage; profiler.start("SET_EXTRA_DATA"); extraData = new ExtraDataEntity(requisition.getExtraData()); @@ -405,10 +408,9 @@ public void updateFrom(Requisition requisition, Map products, + Map approvedProducts, + RequisitionService requisitionService, PeriodService periodService, Profiler profiler) { + if (emergency) { + LOGGER.debug("Calculation and validation skipped for emergency requisition " + + "with following id: {}", id); + return; + } + + if (!template.isPopulateStockOnHandFromStockCards()) { + calculateAndValidateNonStockTemplateFields(products, approvedProducts); + return; + } + + ProcessingPeriodDto period = periodService.getPeriod(requisition.getProcessingPeriodId()); + List previousPeriods = periodService + .findPreviousPeriods(period, template.getNumberOfPeriodsToAverage() - 1); + + List stockCardRangeSummaries = + requisitionService.getStockCardRangeSummaries(requisition, period, profiler); + + List stockCardRangeSummariesToAverage; + if (previousPeriods.size() > 1) { + stockCardRangeSummariesToAverage = + requisitionService.getStockCardRangeSummariesToAverage(requisition, + period, previousPeriods, profiler); + } else { + stockCardRangeSummariesToAverage = stockCardRangeSummaries; + } + + previousPeriods.add(period); + + calculateAndValidateStockTemplateFields(products, approvedProducts, + stockCardRangeSummariesToAverage, stockCardRangeSummaries, previousPeriods); + } + /** * Initiates the state of a requisition by creating line items based on products. * @@ -631,10 +670,11 @@ private Integer extractIdealStockAmount(Map idealStockAmounts, /** * Submits this requisition. - * */ public void submit(Map products, UUID submitter, - boolean skipAuthorize) { + boolean skipAuthorize, ProcessingPeriodDto period, + RequisitionService requisitionService, PeriodService periodService, + Profiler profiler) { if (!status.isSubmittable()) { throw new ValidationMessageException( new Message(ERROR_MUST_BE_INITIATED_TO_BE_SUBMMITED, getId())); @@ -660,7 +700,7 @@ public void submit(Map products, UUID submitte }); } - updateConsumptions(products); + updateConsumptions(products, period, requisitionService, periodService, profiler); updateTotalCostAndPacksToShip(products); status = RequisitionStatus.SUBMITTED; @@ -674,17 +714,21 @@ public void submit(Map products, UUID submitte } /** - * Authorize this Requisition. + * Authorize this requisition. * */ - public void authorize(Map products, UUID authorizer) { + public void authorize(Map products, UUID authorizer, + ProcessingPeriodDto period, + RequisitionService requisitionService, PeriodService periodService, + Profiler profiler) { if (!RequisitionStatus.SUBMITTED.equals(status)) { throw new ValidationMessageException( new Message(ERROR_MUST_BE_SUBMITTED_TO_BE_AUTHORIZED, getId())); } - updateConsumptions(products); + updateConsumptions(products, period, requisitionService, periodService, profiler); updateTotalCostAndPacksToShip(products); + prepareRequisitionForApproval(authorizer); setModifiedDate(ZonedDateTime.now()); } @@ -716,7 +760,7 @@ public boolean isApproved() { /** - * Approves given requisition. + * Approves this requisition. * * @param nodeId supervisoryNode that has a supply line for the requisition's program. * @param products orderable products that will be used by line items to update packs to ship. @@ -725,7 +769,9 @@ public boolean isApproved() { * @param approver user who approves this requisition. */ public void approve(UUID nodeId, Map products, - Collection supplyLines, UUID approver) { + Collection supplyLines, UUID approver, + ProcessingPeriodDto period, RequisitionService requisitionService, + PeriodService periodService, Profiler profiler) { if (isTrue(reportOnly)) { status = RequisitionStatus.RELEASED_WITHOUT_ORDER; } else { @@ -737,19 +783,22 @@ public void approve(UUID nodeId, Map products, } } - updateConsumptions(products); + updateConsumptions(products, period, requisitionService, periodService, profiler); updateTotalCostAndPacksToShip(products); - setModifiedDate(ZonedDateTime.now()); + setModifiedDate(ZonedDateTime.now()); statusChanges.add(StatusChange.newStatusChange(this, approver)); } /** - * Rejects given requisition. + * Rejects this requisition. */ - public void reject(Map products, UUID rejector) { + public void reject(Map products, UUID rejector, + ProcessingPeriodDto period, RequisitionService requisitionService, + PeriodService periodService, Profiler profiler) { status = RequisitionStatus.REJECTED; - updateConsumptions(products); + + updateConsumptions(products, period, requisitionService, periodService, profiler); updateTotalCostAndPacksToShip(products); setModifiedDate(ZonedDateTime.now()); supervisoryNodeId = null; @@ -1050,7 +1099,7 @@ private Money calculateTotalCostForLines(List requisitionLi .orElseGet(() -> Money.of(CurrencyUnit.of(currencyCode), 0)); } - private void calculateAndValidateTemplateFields(RequisitionTemplate template, + private void calculateAndValidateNonStockTemplateFields( Map orderables, Map approvedProducts) { getNonSkippedFullSupplyRequisitionLineItems(orderables) @@ -1059,7 +1108,48 @@ private void calculateAndValidateTemplateFields(RequisitionTemplate template, numberOfMonthsInPeriod, approvedProducts)); } - private void updateConsumptions(Map orderables) { + private void calculateAndValidateStockTemplateFields( + Map orderables, + Map approvedProducts, + List stockCardRangeSummariesToAverage, + List stockCardRangeSummaries, + List periods) { + getNonSkippedFullSupplyRequisitionLineItems(orderables) + .forEach(line -> { + StockCardRangeSummaryDto stockCardRangeSummaryToAverage = findStockCardRangeSummary( + stockCardRangeSummariesToAverage, line.getOrderable().getId()); + + StockCardRangeSummaryDto stockCardRangeSummary = findStockCardRangeSummary( + stockCardRangeSummaries, line.getOrderable().getId()); + + line.calculateAndSetStockFields(stockCardRangeSummaryToAverage, + stockCardRangeSummary, template, periods, previousRequisitions, + numberOfMonthsInPeriod, approvedProducts); + }); + } + + private void updateConsumptions(Map orderables, + ProcessingPeriodDto period, + RequisitionService requisitionService, + PeriodService periodService, Profiler profiler) { + if (!getTemplate().isPopulateStockOnHandFromStockCards()) { + updateNonStockConsumptions(orderables); + return; + } + + List previousPeriods = periodService + .findPreviousPeriods(period, getTemplate().getNumberOfPeriodsToAverage() - 1); + + List stockCardRangeSummariesToAverage = + requisitionService.getStockCardRangeSummariesToAverage( + this, period, previousPeriods, profiler); + + previousPeriods.add(period); + + updateStockConsumptions(orderables, stockCardRangeSummariesToAverage, previousPeriods); + } + + private void updateNonStockConsumptions(Map orderables) { if (template.isColumnInTemplateAndDisplayed(ADJUSTED_CONSUMPTION)) { getNonSkippedFullSupplyRequisitionLineItems(orderables) .forEach(line -> line.setAdjustedConsumption( @@ -1074,6 +1164,34 @@ private void updateConsumptions(Map orderables } } + private void updateStockConsumptions( + Map orderables, + List stockCardRangeSummariesToAverage, + List periods) { + if (!template.isColumnInTemplateAndDisplayed(ADJUSTED_CONSUMPTION) + && !template.isColumnInTemplateAndDisplayed(AVERAGE_CONSUMPTION)) { + return; + } + + for (RequisitionLineItem line: getNonSkippedFullSupplyRequisitionLineItems(orderables)) { + if (template.isColumnInTemplateAndDisplayed(ADJUSTED_CONSUMPTION)) { + line.setAdjustedConsumption( + LineItemFieldsCalculator.calculateAdjustedConsumption( + line, numberOfMonthsInPeriod, + this.template.isColumnInTemplateAndDisplayed(ADDITIONAL_QUANTITY_REQUIRED)) + ); + } + + if (template.isColumnInTemplateAndDisplayed(AVERAGE_CONSUMPTION)) { + StockCardRangeSummaryDto summaryToAverage = findStockCardRangeSummary( + stockCardRangeSummariesToAverage, line.getOrderable().getId()); + + line.calculateAndSetStockBasedAverageConsumption(summaryToAverage, + template, periods, previousRequisitions); + } + } + } + private void updateTotalCostAndPacksToShip(Map products) { getNonSkippedRequisitionLineItems() .forEach(line -> { diff --git a/src/main/java/org/openlmis/requisition/domain/requisition/RequisitionLineItem.java b/src/main/java/org/openlmis/requisition/domain/requisition/RequisitionLineItem.java index 3a92aee94..cc9b9118b 100644 --- a/src/main/java/org/openlmis/requisition/domain/requisition/RequisitionLineItem.java +++ b/src/main/java/org/openlmis/requisition/domain/requisition/RequisitionLineItem.java @@ -620,6 +620,28 @@ void calculateAndSetFields(RequisitionTemplate template, calculateAndSetCalculatedOrderQuantityIsa(template); } + /** + * Calculate and set all calculated stock fields in this requisition line item. + */ + void calculateAndSetStockFields(StockCardRangeSummaryDto stockCardRangeSummaryToAverage, + StockCardRangeSummaryDto stockCardRangeSummary, + RequisitionTemplate template, + List periods, + List previousRequisitions, + Integer numberOfMonthsInPeriod, + Map approvedProducts) { + calculateAndSetStockBasedTotalLossesAndAdjustments(template, stockCardRangeSummary); + calculateAndSetStockOnHand(template); + calculateAndSetStockBasedTotalConsumedQuantity(template, stockCardRangeSummary); + calculateAndSetTotal(template); + calculateAndSetAdjustedConsumption(template, numberOfMonthsInPeriod); + calculateAndSetStockBasedAverageConsumption(stockCardRangeSummaryToAverage, + template, periods, previousRequisitions); + calculateAndSetMaximumStockQuantity(template, approvedProducts); + calculateAndSetCalculatedOrderQuantity(template, approvedProducts); + calculateAndSetCalculatedOrderQuantityIsa(template); + } + /** * Sets value to Total Consumed Quantity column based on stock range summaries. */ @@ -662,10 +684,12 @@ void calculateAndSetStockBasedTotalLossesAndAdjustments(RequisitionTemplate temp void calculateAndSetStockBasedAverageConsumption( StockCardRangeSummaryDto stockCardRangeSummaryToAverage, RequisitionTemplate template, List periods, List previousRequisitions) { - setAverageConsumption(calculateStockBasedAverageConsumption(stockCardRangeSummaryToAverage, - this.orderable.getId(), template, periods, - template.isColumnDisplayed(ADDITIONAL_QUANTITY_REQUIRED) - ? getSumOfAdditionalQuantitiesFromPreviousLineItems(previousRequisitions) : null)); + if (template.isColumnInTemplate(AVERAGE_CONSUMPTION)) { + setAverageConsumption(calculateStockBasedAverageConsumption(stockCardRangeSummaryToAverage, + this.orderable.getId(), template, periods, + template.isColumnDisplayed(ADDITIONAL_QUANTITY_REQUIRED) + ? getSumOfAdditionalQuantitiesFromPreviousLineItems(previousRequisitions) : null)); + } } /** diff --git a/src/main/java/org/openlmis/requisition/repository/RequisitionRepository.java b/src/main/java/org/openlmis/requisition/repository/RequisitionRepository.java index c93c8a449..d0e933f81 100644 --- a/src/main/java/org/openlmis/requisition/repository/RequisitionRepository.java +++ b/src/main/java/org/openlmis/requisition/repository/RequisitionRepository.java @@ -35,7 +35,7 @@ public interface RequisitionRepository extends BaseAuditableRepository { List findByTemplateId(@Param("templateId") UUID templateId); - @EntityGraph(attributePaths = { "requisitionLineItems" }, type = EntityGraphType.LOAD) + @EntityGraph(attributePaths = {"requisitionLineItems"}, type = EntityGraphType.LOAD) List readDistinctByIdIn(Iterable ids); @Query(value = "SELECT\n" @@ -62,4 +62,4 @@ public interface RequisitionRepository extends nativeQuery = true ) boolean existsByOriginalRequisitionId(@Param("originalRequisitionId") UUID originalRequisitionId); -} +} \ No newline at end of file diff --git a/src/main/java/org/openlmis/requisition/service/PeriodService.java b/src/main/java/org/openlmis/requisition/service/PeriodService.java index 52479dd3f..2d61704dd 100644 --- a/src/main/java/org/openlmis/requisition/service/PeriodService.java +++ b/src/main/java/org/openlmis/requisition/service/PeriodService.java @@ -194,12 +194,8 @@ public Collection getPeriods( * @param amount of previous periods * @return list previous period or {@code null} if not found. */ - List findPreviousPeriods(UUID periodId, int amount) { + public List findPreviousPeriods(UUID periodId, int amount) { ProcessingPeriodDto period = getPeriod(periodId); - if (null == period) { - return Collections.emptyList(); - } - return findPreviousPeriods(period, amount); } @@ -210,7 +206,11 @@ List findPreviousPeriods(UUID periodId, int amount) { * @param amount of previous periods * @return previous period or {@code null} if not found. */ - List findPreviousPeriods(ProcessingPeriodDto period, int amount) { + public List findPreviousPeriods(ProcessingPeriodDto period, int amount) { + if (null == period) { + return Collections.emptyList(); + } + return periodReferenceDataService.search( period.getProcessingSchedule().getId(), period.getStartDate().minusDays(1), diff --git a/src/main/java/org/openlmis/requisition/service/RequisitionService.java b/src/main/java/org/openlmis/requisition/service/RequisitionService.java index 9db2a7369..d45b76925 100644 --- a/src/main/java/org/openlmis/requisition/service/RequisitionService.java +++ b/src/main/java/org/openlmis/requisition/service/RequisitionService.java @@ -93,6 +93,7 @@ import org.openlmis.requisition.repository.custom.RequisitionSearchParams; import org.openlmis.requisition.service.fulfillment.OrderFulfillmentService; import org.openlmis.requisition.service.referencedata.ApproveProductsAggregator; +import org.openlmis.requisition.service.referencedata.ApprovedProductReferenceDataService; import org.openlmis.requisition.service.referencedata.IdealStockAmountReferenceDataService; import org.openlmis.requisition.service.referencedata.PermissionStringDto; import org.openlmis.requisition.service.referencedata.PermissionStrings; @@ -187,6 +188,9 @@ public class RequisitionService { @Autowired private FacilitySupportsProgramHelper facilitySupportsProgramHelper; + @Autowired + private ApprovedProductReferenceDataService approvedProductReferenceDataService; + /** * Initiated given requisition if possible. * @@ -341,7 +345,9 @@ public void delete(Requisition requisition) { */ public Requisition reject(Requisition requisition, Map orderables, - List rejections) { + List rejections, ProcessingPeriodDto period, + RequisitionService requisitionService, PeriodService periodService, + Profiler profiler) { checkIfRejectable(requisition); UserDto currentUser = authenticationHelper.getCurrentUser(); @@ -349,7 +355,7 @@ public Requisition reject(Requisition requisition, validateCanApproveRequisition(requisition, userId).throwExceptionIfHasErrors(); LOGGER.debug("Requisition rejected: {}", requisition.getId()); - requisition.reject(orderables, userId); + requisition.reject(orderables, userId, period, requisitionService, periodService, profiler); requisition.setSupervisoryNodeId(null); saveStatusMessage(requisition, currentUser); Requisition savedRequisition = requisitionRepository.save(requisition); @@ -794,8 +800,10 @@ public void saveStatusMessage(Requisition requisition, UserDto currentUser) { */ public void doApprove(UUID parentNodeId, UserDto currentUser, Map orderables, - Requisition requisition, List supplyLines) { - requisition.approve(parentNodeId, orderables, supplyLines, currentUser.getId()); + Requisition requisition, List supplyLines, + ProcessingPeriodDto period, Profiler profiler) { + requisition.approve(parentNodeId, orderables, supplyLines, currentUser.getId(), period, this, + periodService, profiler); saveStatusMessage(requisition, currentUser); requisitionRepository.saveAndFlush(requisition); @@ -1057,4 +1065,50 @@ private Long calculateCurrentlyCreatedRequisitions( ); } + + /** + * Retrieves stockCardRangeSummariesToAverage from certain requisition. + * @param requisition - requisition + * @param profiler - java profiler + * @return retrieved list of stockCardRangeSummariesToAverage. + */ + public List getStockCardRangeSummariesToAverage( + Requisition requisition, ProcessingPeriodDto period, + List previousPeriods, Profiler profiler) { + profiler.start("FIND_APPROVED_PRODUCTS"); + ApproveProductsAggregator approvedProducts = approvedProductReferenceDataService + .getApprovedProducts(requisition.getFacilityId(), requisition.getProgramId()); + + LocalDate startDate = previousPeriods.size() <= 1 + ? period.getStartDate() : + previousPeriods.get(previousPeriods.size() - 1).getStartDate(); + + profiler.start("FIND_STOCK_CARD_RANGE_SUMMARIES_TO_AVERAGE"); + return stockCardRangeSummaryStockManagementService + .search(requisition.getProgramId(), requisition.getFacilityId(), + approvedProducts.getOrderableIdentities(), null, + startDate, period.getEndDate()); + } + + /** + * Retrieves stockCardRangeSummaries from certain requisition. + * @param requisition - requisition + * @param period - period + * @param profiler - java profiler + * @return retrieved list of StockCardRangeSummaryDto. + */ + public List getStockCardRangeSummaries(Requisition requisition, + ProcessingPeriodDto period, + Profiler profiler) { + profiler.start("FIND_APPROVED_PRODUCTS"); + ApproveProductsAggregator approvedProducts = approvedProductReferenceDataService + .getApprovedProducts(requisition.getFacilityId(), requisition.getProgramId()); + + profiler.start("FIND_STOCK_CARD_RANGE_SUMMARIES"); + return stockCardRangeSummaryStockManagementService + .search(requisition.getProgramId(), requisition.getFacilityId(), + approvedProducts.getOrderableIdentities(), null, + period.getStartDate(), period.getEndDate()); + } + } diff --git a/src/main/java/org/openlmis/requisition/service/referencedata/PeriodReferenceDataService.java b/src/main/java/org/openlmis/requisition/service/referencedata/PeriodReferenceDataService.java index 9e97851b9..57a9925f5 100644 --- a/src/main/java/org/openlmis/requisition/service/referencedata/PeriodReferenceDataService.java +++ b/src/main/java/org/openlmis/requisition/service/referencedata/PeriodReferenceDataService.java @@ -110,6 +110,20 @@ public List search(Set periodIds) { return getPage(parameters).getContent(); } + /** + * This method retrieves processing period for given id. + * + * @param periodId period id. + * @return ProcessingPeriodDto. + */ + public ProcessingPeriodDto searchById(UUID periodId) { + RequestParameters parameters = RequestParameters + .init() + .set("id", periodId); + + return findOne(getUrl(), parameters); + } + /** * Retrieves periods from the reference data service by program ID and facility ID. * diff --git a/src/main/java/org/openlmis/requisition/web/BaseRequisitionController.java b/src/main/java/org/openlmis/requisition/web/BaseRequisitionController.java index c630967c2..7e5d7856a 100644 --- a/src/main/java/org/openlmis/requisition/web/BaseRequisitionController.java +++ b/src/main/java/org/openlmis/requisition/web/BaseRequisitionController.java @@ -291,6 +291,11 @@ UpdatePreparationResult doUpdatePreparation(UUID requisitionId, period, requisitionToUpdate.getStatus(), orderables, productReferences); requisition.setId(requisitionId); + requisition.setProcessingPeriodId(period.getId()); + requisition.setTemplate(requisitionToUpdate.getTemplate()); + requisition.setProgramId(requisitionImporter.getProgramId()); + requisition.setFacilityId(requisitionImporter.getFacilityId()); + ProgramDto program = findProgram(requisitionToUpdate.getProgramId(), profiler); profiler.start("VALIDATE_CAN_BE_UPDATED"); @@ -357,7 +362,6 @@ void doApprove(Requisition requisition, ApproveParams approveParams) { approveRequisition(requisition, approveParams, parentNodeId, profiler); } - logger.debug("Requisition with id {} approved", requisition.getId()); stopProfiler(profiler); } @@ -400,7 +404,7 @@ private void approveRequisition(Requisition requisition, ApproveParams approvePa UUID parentNodeId, Profiler profiler) { profiler.start("DO_APPROVE"); requisitionService.doApprove(parentNodeId, approveParams.user, approveParams.orderables, - requisition, approveParams.supplyLines); + requisition, approveParams.supplyLines, approveParams.period, profiler); if (requisition.getStatus().isApproved() && !isEmpty(approveParams.supplyLines)) { profiler.start("RETRIEVE_SUPPLYING_FACILITY"); @@ -698,7 +702,7 @@ class UpdateParams { void updateAndSave(Profiler profiler) { profiler.start("UPDATE"); toUpdate.updateFrom(requisition, orderables, approvedProducts, - datePhysicalStockCountCompletedEnabledPredicate.exec(program)); + datePhysicalStockCountCompletedEnabledPredicate.exec(program), null, null); profiler.start("SAVE"); toUpdate = requisitionRepository.save(toUpdate); diff --git a/src/main/java/org/openlmis/requisition/web/RequisitionController.java b/src/main/java/org/openlmis/requisition/web/RequisitionController.java index bb68afd10..5d9099429 100644 --- a/src/main/java/org/openlmis/requisition/web/RequisitionController.java +++ b/src/main/java/org/openlmis/requisition/web/RequisitionController.java @@ -223,7 +223,7 @@ public BasicRequisitionDto submitRequisition( profiler.start("SUBMIT"); requisition.submit(orderables, getCurrentUser(profiler).getId(), - program.getSkipAuthorization()); + program.getSkipAuthorization(), period, requisitionService, periodService, profiler); profiler.start("SAVE"); requisitionService.saveStatusMessage(requisition, authenticationHelper.getCurrentUser()); @@ -396,9 +396,11 @@ public BasicRequisitionDto rejectRequisition( profiler, () -> getLineItemOrderableIdentities(requisition) ); + ProcessingPeriodDto period = periodService.getPeriod(requisition.getProcessingPeriodId()); + profiler.start("REJECT"); Requisition rejectedRequisition = requisitionService.reject(requisition, orderables, - rejections); + rejections, period, requisitionService, periodService, profiler); callStatusChangeProcessor(profiler, rejectedRequisition); @@ -601,7 +603,8 @@ public BasicRequisitionDto authorizeRequisition( UserDto user = getCurrentUser(profiler); profiler.start("AUTHORIZE"); - requisition.authorize(orderables, user.getId()); + requisition.authorize(orderables, user.getId(), period, + requisitionService, periodService, profiler); profiler.start("SAVE"); requisitionService.saveStatusMessage(requisition, user); diff --git a/src/main/java/org/openlmis/requisition/web/RequisitionV2Controller.java b/src/main/java/org/openlmis/requisition/web/RequisitionV2Controller.java index eaf207d4a..dfcc6777b 100644 --- a/src/main/java/org/openlmis/requisition/web/RequisitionV2Controller.java +++ b/src/main/java/org/openlmis/requisition/web/RequisitionV2Controller.java @@ -43,6 +43,7 @@ import org.openlmis.requisition.dto.RequisitionLineItemV2Dto; import org.openlmis.requisition.dto.RequisitionV2Dto; import org.openlmis.requisition.dto.VersionObjectReferenceDto; +import org.openlmis.requisition.service.PeriodService; import org.openlmis.requisition.service.RequisitionService; import org.slf4j.profiler.Profiler; import org.springframework.beans.factory.annotation.Autowired; @@ -70,6 +71,9 @@ public class RequisitionV2Controller extends BaseRequisitionController { @Autowired private RequisitionService requisitionService; + @Autowired + private PeriodService periodService; + public static final String RESOURCE_URL = API_URL + "/v2/requisitions"; @Value("${service.url}") @@ -133,7 +137,8 @@ public RequisitionV2Dto updateRequisition(@PathVariable("id") UUID requisitionId profiler.start("UPDATE"); requisitionToUpdate.updateFrom(result.getRequisition(), result.getOrderables(), result.getApprovedProducts(), - datePhysicalStockCountCompletedEnabledPredicate.exec(result.getProgram())); + datePhysicalStockCountCompletedEnabledPredicate.exec(result.getProgram()), + requisitionService, periodService); requisitionService.processUnSkippedRequisitionLineItems(requisitionToUpdate, LocaleContextHolder.getLocale()); diff --git a/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionDataBuilder.java b/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionDataBuilder.java index 8955448fc..828ce9d45 100644 --- a/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionDataBuilder.java +++ b/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionDataBuilder.java @@ -303,6 +303,11 @@ public RequisitionDataBuilder withNumberOfMonthsInPeriod( return this; } + public RequisitionDataBuilder withPreviousRequisitions(List previousRequisitions) { + this.previousRequisitions = previousRequisitions; + return this; + } + /** * Sets stock adjustment reasons. */ diff --git a/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionLineItemTest.java b/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionLineItemTest.java index 21cb1b6b5..4b0b3d50e 100644 --- a/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionLineItemTest.java +++ b/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionLineItemTest.java @@ -30,7 +30,9 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.openlmis.requisition.domain.SourceType.CALCULATED; import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.ADDITIONAL_QUANTITY_REQUIRED; +import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.AVERAGE_CONSUMPTION; import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.TOTAL_CONSUMED_QUANTITY; import com.google.common.collect.ImmutableMap; @@ -670,6 +672,7 @@ public void shouldCalculateStockBasedAverageConsumptionWithoutAdditionalQuantiti RequisitionTemplate template = new RequisitionTemplateDataBuilder() .withColumn(ADDITIONAL_QUANTITY_REQUIRED, COLUMN_IDENTIFIER, SourceType.USER_INPUT, singleton(SourceType.USER_INPUT), false) + .withColumn(AVERAGE_CONSUMPTION, null, CALCULATED, Sets.newHashSet(CALCULATED)) .withStockBasedColumn(TOTAL_CONSUMED_QUANTITY, COLUMN_IDENTIFIER, CONSUMED_TAG) .withNumberOfPeriodsToAverage(2) .build(); diff --git a/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionTest.java b/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionTest.java index 4e9d22929..863d653b3 100644 --- a/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionTest.java +++ b/src/test/java/org/openlmis/requisition/domain/requisition/RequisitionTest.java @@ -89,6 +89,8 @@ import org.openlmis.requisition.dto.VersionIdentityDto; import org.openlmis.requisition.dto.stockmanagement.StockCardRangeSummaryDto; import org.openlmis.requisition.exception.ValidationMessageException; +import org.openlmis.requisition.service.PeriodService; +import org.openlmis.requisition.service.RequisitionService; import org.openlmis.requisition.testutils.ApprovedProductDtoDataBuilder; import org.openlmis.requisition.testutils.DtoGenerator; import org.openlmis.requisition.testutils.OrderableDtoDataBuilder; @@ -99,6 +101,7 @@ import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import org.slf4j.profiler.Profiler; @PrepareForTest({LineItemFieldsCalculator.class}) @RunWith(PowerMockRunner.class) @@ -198,7 +201,8 @@ public void shouldChangeStatusToRejectedAfterReject() { requisition.setStatus(RequisitionStatus.AUTHORIZED); // when - requisition.reject(orderables, UUID.randomUUID()); + requisition.reject(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); // then assertEquals(requisition.getStatus(), RequisitionStatus.REJECTED); @@ -208,7 +212,8 @@ public void shouldChangeStatusToRejectedAfterReject() { public void shouldSubmitRequisitionIfItsStatusIsInitiated() { requisition.setTemplate(mock(RequisitionTemplate.class)); requisition.setStatus(RequisitionStatus.INITIATED); - requisition.submit(orderables, UUID.randomUUID(), false); + requisition.submit(orderables, UUID.randomUUID(), false, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.SUBMITTED); } @@ -217,7 +222,9 @@ public void shouldSubmitRequisitionIfItsStatusIsInitiated() { public void shouldSubmitRequisitionIfItsStatusIsRejected() { requisition.setTemplate(mock(RequisitionTemplate.class)); requisition.setStatus(RequisitionStatus.REJECTED); - requisition.submit(orderables, UUID.randomUUID(), false); + requisition.submit(orderables, UUID.randomUUID(), false, + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.SUBMITTED); } @@ -226,7 +233,9 @@ public void shouldSubmitRequisitionIfItsStatusIsRejected() { public void shouldSubmitRequisitionAndMarkAsAuthorizedWhenAuthorizeIsSkipped() { requisition.setTemplate(mock(RequisitionTemplate.class)); requisition.setStatus(RequisitionStatus.INITIATED); - requisition.submit(orderables, UUID.randomUUID(), true); + requisition.submit(orderables, UUID.randomUUID(), true, + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.AUTHORIZED); } @@ -234,12 +243,16 @@ public void shouldSubmitRequisitionAndMarkAsAuthorizedWhenAuthorizeIsSkipped() { @Test public void shouldNotSubmitRegularRequisitionIfRegularFieldsNotFilled() { prepareRequisitionToHaveRequiredFieldStockOnHandNotFilled(); - assertThatThrownBy(() -> requisition.submit(orderables, UUID.randomUUID(), false)) + assertThatThrownBy(() -> requisition.submit(orderables, UUID.randomUUID(), false, + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class))) .isInstanceOf(ValidationMessageException.class) .hasMessage(getRequiredFieldErrorMessage(STOCK_ON_HAND, TOTAL_CONSUMED_QUANTITY)); prepareRequisitionToHaveRequiredFieldTotalConsumedQuantityNotFilled(); - assertThatThrownBy(() -> requisition.submit(orderables, UUID.randomUUID(), false)) + assertThatThrownBy(() -> requisition.submit(orderables, UUID.randomUUID(), false, + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class))) .isInstanceOf(ValidationMessageException.class) .hasMessage(getRequiredFieldErrorMessage(TOTAL_CONSUMED_QUANTITY, STOCK_ON_HAND)); @@ -251,7 +264,8 @@ public void shouldSubmitEmergencyRequisitionIfRegularFieldsNotFilled() { prepareRequisitionToHaveRequiredFieldStockOnHandNotFilled(); requisition.setEmergency(true); - requisition.submit(orderables, UUID.randomUUID(), false); + requisition.submit(orderables, UUID.randomUUID(), false, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.SUBMITTED); } @@ -260,7 +274,8 @@ public void shouldSubmitEmergencyRequisitionIfRegularFieldsNotFilled() { public void shouldAuthorizeRequisitionIfItsStatusIsSubmitted() { requisition.setTemplate(mock(RequisitionTemplate.class)); requisition.setStatus(RequisitionStatus.SUBMITTED); - requisition.authorize(orderables, UUID.randomUUID()); + requisition.authorize(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.AUTHORIZED); } @@ -272,7 +287,8 @@ public void shouldInApprovalRequisitionIfItsStatusIsAuthorizedAndParentNodeExist SupervisoryNodeDto parentNode = mockSupervisoryParentNode(UUID.randomUUID()); requisition.approve(parentNode.getId(), orderables, Collections.emptyList(), - UUID.randomUUID()); + UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.IN_APPROVAL); } @@ -284,7 +300,8 @@ public void shouldInApprovalRequisitionIfItsStatusIsInApprovalAndParentNodeExist SupervisoryNodeDto parentNode = mockSupervisoryParentNode(UUID.randomUUID()); requisition.approve(parentNode.getId(), orderables, Collections.emptyList(), - UUID.randomUUID()); + UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.IN_APPROVAL); } @@ -297,7 +314,8 @@ public void shouldApproveRequisitionIfItsStatusIsAuthorizedAndParentNodeDoesNotE SupplyLineDto supplyLine = new SupplyLineDtoDataBuilder().buildAsDto(); requisition.approve(parentNode.getId(), orderables, - Collections.singletonList(supplyLine), UUID.randomUUID()); + Collections.singletonList(supplyLine), UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.APPROVED); } @@ -310,7 +328,8 @@ public void shouldApproveRequisitionIfItsStatusIsInApprovalAndParentNodeNotExist SupplyLineDto supplyLine = new SupplyLineDtoDataBuilder().buildAsDto(); requisition.approve(parentNode.getId(), orderables, - Collections.singletonList(supplyLine), UUID.randomUUID()); + Collections.singletonList(supplyLine), UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(requisition.getStatus(), RequisitionStatus.APPROVED); } @@ -318,7 +337,8 @@ public void shouldApproveRequisitionIfItsStatusIsInApprovalAndParentNodeNotExist @Test(expected = ValidationMessageException.class) public void shouldThrowExceptionWhenAuthorizingRequisitionWithNotSubmittedStatus() { requisition.setTemplate(mock(RequisitionTemplate.class)); - requisition.authorize(orderables, UUID.randomUUID()); + requisition.authorize(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); } @Test @@ -340,8 +360,10 @@ public void shouldCalculateStockOnHandForRequisitionLineItemsWhenAuthorizing() { requisition.setTemplate(requisitionTemplate); requisition.setStatus(RequisitionStatus.SUBMITTED); - requisition.authorize(orderables, UUID.randomUUID()); - requisition.updateFrom(new Requisition(), orderables, approvedProducts,true); + requisition.authorize(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); + requisition.updateFrom(mockNonStockmanagementRequisition(), orderables, approvedProducts, + true, null, null); assertEquals(requisition.getStatus(), RequisitionStatus.AUTHORIZED); verifyStatic(LineItemFieldsCalculator.class); @@ -358,7 +380,8 @@ public void shouldDefaultApprovedQuantityOnAuthorizeWhenCalcOrderQuantityColumnD requisitionLineItem.setRequestedQuantity(null); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(CALCULATED_ORDER_QUANTITY), requisitionLineItem.getApprovedQuantity()); @@ -379,7 +402,8 @@ public void shouldDefaultApprovedQuantityOnAuthorizeWhenCalcOrderQuantityIsaColu requisitionLineItem.setRequestedQuantity(null); requisitionLineItem.setCalculatedOrderQuantityIsa(100); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(100), requisitionLineItem.getApprovedQuantity()); } @@ -394,7 +418,8 @@ public void shouldDefaultApprovedQuantityOnSubmitWhenAuthorizationStepSkipped() requisitionLineItem.setRequestedQuantity(null); - requisition.submit(orderables, null, true); + requisition.submit(orderables, null, true, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(CALCULATED_ORDER_QUANTITY), requisitionLineItem.getApprovedQuantity()); @@ -408,7 +433,8 @@ public void shouldPopulateWithReqQuantityWhenIsNotNullAndCalcOrderQuantityColumn when(template.isColumnDisplayed(RequisitionLineItem.CALCULATED_ORDER_QUANTITY)) .thenReturn(true); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(REQUESTED_QUANTITY), requisitionLineItem.getApprovedQuantity()); } @@ -423,7 +449,8 @@ public void shouldPopulateWithRequestedQuantityWhenCalculatedOrderQuantityIsNotD requisitionLineItem.setRequestedQuantity(REQUESTED_QUANTITY); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(REQUESTED_QUANTITY), requisitionLineItem.getApprovedQuantity()); } @@ -442,7 +469,8 @@ public void shouldPopulateWithRequestedQuantityWhenCalculatedOrderQuantityIsaIsN requisitionLineItem.setRequestedQuantity(REQUESTED_QUANTITY); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(REQUESTED_QUANTITY), requisitionLineItem.getApprovedQuantity()); } @@ -459,7 +487,8 @@ public void shouldPopulateWithRequestedQuantityWhenCalculatedOrderQuantityIsaNot requisitionLineItem.setRequestedQuantity(REQUESTED_QUANTITY); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(REQUESTED_QUANTITY), requisitionLineItem.getApprovedQuantity()); } @@ -474,7 +503,8 @@ public void shouldPopulateNonFullSupplyLineItems() { requisitionLineItem.setRequestedQuantity(REQUESTED_QUANTITY); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertEquals(Integer.valueOf(REQUESTED_QUANTITY), requisitionLineItem.getApprovedQuantity()); } @@ -489,7 +519,8 @@ public void shouldPopulateWithNullRequestedQuantityWhenCalculatedOrderQuantityIs requisitionLineItem.setRequestedQuantity(null); - requisition.authorize(orderables, null); + requisition.authorize(orderables, null, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertNull(requisitionLineItem.getApprovedQuantity()); } @@ -510,7 +541,8 @@ public void shouldCalculateTotalValueWhenUpdatingRequisition() { Collections.singletonList(requisitionLineItem))); requisition.setTemplate(requisitionTemplate); - requisition.updateFrom(new Requisition(), orderables, approvedProducts,true); + requisition.updateFrom(mockNonStockmanagementRequisition(), orderables, approvedProducts, + true, null, null); verifyStatic(LineItemFieldsCalculator.class); LineItemFieldsCalculator.calculateStockOnHand(any(RequisitionLineItem.class)); } @@ -542,7 +574,7 @@ public void shouldAddFullSupplyLinesForEmergencyRequisition() { newRequisition.setRequisitionLineItems(Lists.newArrayList(fullSupply, nonFullSupply)); requisition.setTemplate(mock(RequisitionTemplate.class)); - requisition.updateFrom(newRequisition, orderables, approvedProducts,true); + requisition.updateFrom(newRequisition, orderables, approvedProducts,true, null, null); assertThat(requisition.getRequisitionLineItems(), hasSize(2)); } @@ -574,7 +606,7 @@ public void shouldRemoveFullSupplyLinesForEmergencyRequisition() { newRequisition.setRequisitionLineItems(Lists.newArrayList(nonFullSupply)); requisition.setTemplate(mock(RequisitionTemplate.class)); - requisition.updateFrom(newRequisition, orderables, approvedProducts, true); + requisition.updateFrom(newRequisition, orderables, approvedProducts, true, null, null); assertThat(requisition.getRequisitionLineItems(), hasSize(1)); } @@ -610,6 +642,7 @@ public void shouldSetRequisitionFieldForLineItemsAfterUpdate() { newRequisition.setRequisitionLineItems( Lists.newArrayList(firstRequisitionLineItem, secondRequisitionLineItem) ); + newRequisition.setTemplate(template); newRequisition .getRequisitionLineItems() @@ -624,7 +657,7 @@ public void shouldSetRequisitionFieldForLineItemsAfterUpdate() { // when requisition.setTemplate(template); requisition.setId(UUID.randomUUID()); - requisition.updateFrom(newRequisition, orderables, approvedProducts, true); + requisition.updateFrom(newRequisition, orderables, approvedProducts, true, null, null); // then requisition @@ -642,8 +675,14 @@ public void shouldSetNullForCalculatedValuesIfColumnIsHidden() { when(requisitionTemplate.isColumnDisplayed("stockOnHand")).thenReturn(false); when(requisitionTemplate.isColumnDisplayed(TOTAL_CONSUMED_QUANTITY)).thenReturn(false); + Requisition newRequisition = new Requisition(); + when(requisitionTemplate.isPopulateStockOnHandFromStockCards()).thenReturn(false); + newRequisition.setTemplate(requisitionTemplate); + requisition.setTemplate(requisitionTemplate); - requisition.updateFrom(new Requisition(), orderables, approvedProducts, true); + + requisition.updateFrom(newRequisition, orderables, approvedProducts, + true, null, null); assertThat(requisitionLineItem.getStockOnHand(), is(nullValue())); assertThat(requisitionLineItem.getTotalConsumedQuantity(), is(nullValue())); @@ -904,7 +943,8 @@ public void shouldUpdatePacksToShipOnSubmit() { setUpTestUpdatePacksToShip(orderable, packsToShip); // when - requisition.submit(orderables, UUID.randomUUID(), false); + requisition.submit(orderables, UUID.randomUUID(), false, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); // then assertEquals(packsToShip, requisitionLineItem.getPacksToShip().longValue()); @@ -920,7 +960,8 @@ public void shouldUpdatePacksToShipOnAuthorize() { requisition.setStatus(RequisitionStatus.SUBMITTED); // when - requisition.authorize(orderables, UUID.randomUUID()); + requisition.authorize(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); // then assertEquals(packsToShip, requisitionLineItem.getPacksToShip().longValue()); @@ -935,7 +976,8 @@ public void shouldSetStatusAsReleasedWithoutOrderIfPeriodIsReportOnly() { // when requisition.approve(null, orderables, Collections.emptyList(), - UUID.randomUUID()); + UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); // then assertThat(requisition.getStatus(), is(RequisitionStatus.RELEASED_WITHOUT_ORDER)); @@ -952,7 +994,9 @@ public void shouldUpdatePacksToShipOnApprove() { requisition.setStatus(RequisitionStatus.AUTHORIZED); // when - requisition.approve(null, orderables, Collections.emptyList(), UUID.randomUUID()); + requisition.approve(null, orderables, Collections.emptyList(), UUID.randomUUID(), + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), mock(PeriodService.class), + mock(Profiler.class)); // then assertEquals(packsToShip, requisitionLineItem.getPacksToShip().longValue()); @@ -964,7 +1008,8 @@ public void shouldCalculateAdjustedConsumptionTotalCostAndAverageConsumptionWhen prepareForTestAdjustedConcumptionTotalCostAndAverageConsumption(); //when - requisition.submit(orderables, UUID.randomUUID(), false); + requisition.submit(orderables, UUID.randomUUID(), false, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption().longValue()); @@ -979,7 +1024,8 @@ public void shouldCalculateAdjustedConsumptionTotalCostAndAverageConsumptionWhen requisition.setStatus(RequisitionStatus.AUTHORIZED); //when - requisition.reject(orderables, UUID.randomUUID()); + requisition.reject(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption().longValue()); @@ -998,7 +1044,8 @@ public void shouldCalculateAverageConsumptionWhenSubmitWithOnePreviousRequisitio .thenReturn(AVERAGE_CONSUMPTION); //when - requisition.submit(orderables, UUID.randomUUID(), false); + requisition.submit(orderables, UUID.randomUUID(), false, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption().longValue()); @@ -1018,10 +1065,12 @@ public void shouldCalculateAverageConsumptionWhenSubmitWithManyPreviousRequisiti .thenReturn(AVERAGE_CONSUMPTION); //when - requisition.submit(orderables, UUID.randomUUID(), false); + requisition.submit(orderables, UUID.randomUUID(), false, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then - assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption().longValue()); + assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption() + .longValue()); assertEquals(AVERAGE_CONSUMPTION, requisitionLineItem.getAverageConsumption().longValue()); } @@ -1032,10 +1081,12 @@ public void shouldCalculateAdjustedConsumptionTotalCostAndAverageConsumptionWhen requisition.setStatus(RequisitionStatus.SUBMITTED); //when - requisition.authorize(orderables, UUID.randomUUID()); + requisition.authorize(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then - assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption().longValue()); + assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption() + .longValue()); assertEquals(AVERAGE_CONSUMPTION, requisitionLineItem.getAverageConsumption().longValue()); assertEquals(TOTAL_COST, requisitionLineItem.getTotalCost()); } @@ -1048,17 +1099,20 @@ public void shouldCalculateAdjustedConsumptionTotalCostAndAverageConsumptionWhen //when requisition.approve(null, orderables, Collections.emptyList(), - UUID.randomUUID()); + UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then - assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption().longValue()); + assertEquals(ADJUSTED_CONSUMPTION, requisitionLineItem.getAdjustedConsumption() + .longValue()); assertEquals(AVERAGE_CONSUMPTION, requisitionLineItem.getAverageConsumption().longValue()); assertEquals(TOTAL_COST, requisitionLineItem.getTotalCost()); } @Test public void shouldSetPreviousAdjustedConsumptionsWhenOnePreviousRequisition() { - RequisitionLineItem previousRequisitionLineItem = new RequisitionLineItem(requisitionLineItem); + RequisitionLineItem previousRequisitionLineItem = + new RequisitionLineItem(requisitionLineItem); previousRequisitionLineItem.setAdjustedConsumption(5); Requisition previousRequisition = new Requisition(); @@ -1074,7 +1128,8 @@ public void shouldSetPreviousAdjustedConsumptionsWhenOnePreviousRequisition() { @Test public void shouldSetPreviousAdjustedConsumptionsFromManyPreviousRequisitions() { - RequisitionLineItem previousRequisitionLineItem = new RequisitionLineItem(requisitionLineItem); + RequisitionLineItem previousRequisitionLineItem = + new RequisitionLineItem(requisitionLineItem); previousRequisitionLineItem.setAdjustedConsumption(5); Requisition previousRequisition = new Requisition(); @@ -1112,7 +1167,8 @@ public void shouldNotAddPreviousAdjustedConsumptionIfLineSkipped() { @Test public void shouldNotAddPreviousAdjustedConsumptionIfItIsNull() { //given - RequisitionLineItem previousRequisitionLineItem = new RequisitionLineItem(requisitionLineItem); + RequisitionLineItem previousRequisitionLineItem = + new RequisitionLineItem(requisitionLineItem); previousRequisitionLineItem.setAdjustedConsumption(null); Requisition previousRequisition = new Requisition(); @@ -1143,9 +1199,11 @@ public void shouldNotUpdatePreviousAdjustedConsumptions() { RequisitionTemplate requisitionTemplate = mock(RequisitionTemplate.class); requisition.setTemplate(requisitionTemplate); - requisition.updateFrom(newRequisition, orderables, approvedProducts, true); + newRequisition.setTemplate(requisitionTemplate); + requisition.updateFrom(newRequisition, orderables, approvedProducts, true, null, null); - assertEquals(Integer.valueOf(1), requisitionLineItem.getPreviousAdjustedConsumptions().get(0)); + assertEquals(Integer.valueOf(1), requisitionLineItem.getPreviousAdjustedConsumptions() + .get(0)); } @Test @@ -1167,7 +1225,8 @@ public void shouldRecordStatusChangeOnSubmit() { Requisition requisition = createRequisitionWithStatusOf(RequisitionStatus.INITIATED); requisition.setTemplate(template); - requisition.submit(orderables, submitterId, false); + requisition.submit(orderables, submitterId, false, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertStatusChangeExistsAndAuthorIdMatches(requisition, RequisitionStatus.SUBMITTED, submitterId); @@ -1180,7 +1239,8 @@ public void shouldRecordStatusChangeOnSubmitWithSkippedAuthorization() { requisition.setTemplate(template); requisition.setRequisitionLineItems(Collections.emptyList()); - requisition.submit(orderables, submitterId, true); + requisition.submit(orderables, submitterId, true, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertStatusChangeExistsAndAuthorIdMatches(requisition, RequisitionStatus.SUBMITTED, submitterId); @@ -1195,7 +1255,8 @@ public void shouldRecordStatusChangeOnAuthorize() { requisition.setTemplate(template); requisition.setRequisitionLineItems(Collections.emptyList()); - requisition.authorize(orderables, authorizerId); + requisition.authorize(orderables, authorizerId, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertStatusChangeExistsAndAuthorIdMatches(requisition, RequisitionStatus.AUTHORIZED, authorizerId); @@ -1208,7 +1269,9 @@ public void shouldRecordStatusChangeOnApprove() { requisition.setTemplate(template); requisition.setRequisitionLineItems(Collections.emptyList()); - requisition.approve(null, orderables, Collections.emptyList(), approverId); + requisition.approve(null, orderables, Collections.emptyList(), approverId, + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), mock(PeriodService.class), + mock(Profiler.class)); assertStatusChangeExistsAndAuthorIdMatches(requisition, RequisitionStatus.APPROVED, approverId); @@ -1220,7 +1283,8 @@ public void shouldRecordStatusChangeOnReject() { Requisition requisition = createRequisitionWithStatusOf(RequisitionStatus.AUTHORIZED); requisition.setTemplate(template); - requisition.reject(orderables, rejectorId); + requisition.reject(orderables, rejectorId, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); assertStatusChangeExistsAndAuthorIdMatches(requisition, RequisitionStatus.REJECTED, rejectorId); @@ -1649,7 +1713,8 @@ public void shouldSetApprovedQuantityAccordingToIsaWhenSubmittingStockBasedRequi requisitionLineItem.setCalculatedOrderQuantityIsa(689); //when - requisition.submit(orderables, UUID.randomUUID(), true); + requisition.submit(orderables, UUID.randomUUID(), true, mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then assertEquals( @@ -1671,7 +1736,8 @@ public void shouldSetApprovedQuantityAccordingToIsaWhenAuthorizingStockBasedRequ requisitionLineItem.setCalculatedOrderQuantityIsa(689); //when - requisition.authorize(orderables, UUID.randomUUID()); + requisition.authorize(orderables, UUID.randomUUID(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class)); //then assertEquals( @@ -1681,13 +1747,12 @@ public void shouldSetApprovedQuantityAccordingToIsaWhenAuthorizingStockBasedRequ } private Requisition updateWithDatePhysicalCountCompleted(boolean updateStockDate) { - RequisitionTemplate requisitionTemplate = mock(RequisitionTemplate.class); - this.requisition.setTemplate(requisitionTemplate); - - Requisition requisition = new Requisition(); + Requisition requisition = mockNonStockmanagementRequisition(); requisition.setDatePhysicalStockCountCompleted( new DatePhysicalStockCountCompleted(LocalDate.now())); - this.requisition.updateFrom(requisition, orderables, approvedProducts, updateStockDate); + + this.requisition.updateFrom(requisition, orderables, approvedProducts, updateStockDate, null, + null); return requisition; } @@ -1809,7 +1874,8 @@ private RequisitionLineItem getRequisitionLineItem(boolean skipped, boolean full return item; } - private Requisition getRequisition(RequisitionLineItem notSkipped, RequisitionLineItem skipped) { + private Requisition getRequisition(RequisitionLineItem notSkipped, + RequisitionLineItem skipped) { return new RequisitionDataBuilder() .withProgramId(requisition.getProgramId()) .addLineItem(notSkipped, false) @@ -1848,6 +1914,14 @@ private void mockTemplateWithCalculatedColumn(String column) { requisition.setTemplate(template); } + private Requisition mockNonStockmanagementRequisition() { + Requisition newRequisition = mock(Requisition.class); + RequisitionTemplate newRequisitionTemplate = mock(RequisitionTemplate.class); + when(newRequisition.getTemplate()).thenReturn(newRequisitionTemplate); + when(newRequisitionTemplate.isPopulateStockOnHandFromStockCards()).thenReturn(false); + return newRequisition; + } + private RequisitionTemplate mockStockBasedRequisitionTemplate() { RequisitionTemplate requisitionTemplate = mock(RequisitionTemplate.class); @@ -1860,8 +1934,10 @@ private RequisitionTemplate mockStockBasedRequisitionTemplate() { when(requisitionTemplate.isColumnStockBased(TOTAL_LOSSES_AND_ADJUSTMENTS)).thenReturn(true); when(requisitionTemplate.isColumnStockBased(TOTAL_STOCKOUT_DAYS)).thenReturn(true); - when(requisitionTemplate.findColumn(TOTAL_CONSUMED_QUANTITY)).thenReturn(totalConsumedQuantity); - when(requisitionTemplate.findColumn(TOTAL_RECEIVED_QUANTITY)).thenReturn(totalReceivedQuantity); + when(requisitionTemplate.findColumn(TOTAL_CONSUMED_QUANTITY)) + .thenReturn(totalConsumedQuantity); + when(requisitionTemplate.findColumn(TOTAL_RECEIVED_QUANTITY)) + .thenReturn(totalReceivedQuantity); when(requisitionTemplate.findColumn(TOTAL_LOSSES_AND_ADJUSTMENTS)) .thenReturn(totalLossesAndAdjustments); when(requisitionTemplate.findColumn(TOTAL_STOCKOUT_DAYS)).thenReturn(totalStockoutDays); diff --git a/src/test/java/org/openlmis/requisition/service/RequisitionServiceTest.java b/src/test/java/org/openlmis/requisition/service/RequisitionServiceTest.java index 96ba5e5fa..ef5204ff6 100644 --- a/src/test/java/org/openlmis/requisition/service/RequisitionServiceTest.java +++ b/src/test/java/org/openlmis/requisition/service/RequisitionServiceTest.java @@ -168,6 +168,7 @@ import org.openlmis.requisition.web.FacilitySupportsProgramHelper; import org.openlmis.requisition.web.OrderDtoBuilder; import org.openlmis.requisition.web.RequisitionForConvertBuilder; +import org.slf4j.profiler.Profiler; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -449,7 +450,8 @@ public void shouldRejectRequisitionIfRequisitionStatusIsAuthorized() { any(UUID.class), any(UUID.class), any(UUID.class), any(UUID.class))) .thenReturn(true); Requisition returnedRequisition = requisitionService.reject(requisition, orderables, - generateRejections()); + generateRejections(), mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); assertEquals(returnedRequisition.getStatus(), REJECTED); } @@ -462,7 +464,8 @@ public void shouldRejectRequisitionIfRequisitionStatusIsInApproval() { any(UUID.class), any(UUID.class), any(UUID.class), any(UUID.class))) .thenReturn(true); Requisition returnedRequisition = requisitionService.reject(requisition, orderables, - generateRejections()); + generateRejections(), mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); assertEquals(returnedRequisition.getStatus(), REJECTED); } @@ -476,7 +479,9 @@ public void shouldNotRejectRequisitionIfRequisitionWasSplit() { when(requisitionRepository.existsByOriginalRequisitionId(requisition.getId())) .thenReturn(true); - requisitionService.reject(requisition, emptyMap(), emptyList()); + requisitionService.reject(requisition, emptyMap(), emptyList(), + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); } @Test @@ -487,7 +492,9 @@ public void shouldNotRejectRequisitionIfRequisitionHasOriginalRequisition() { requisition.setStatus(IN_APPROVAL); requisition.setOriginalRequisitionId(UUID.randomUUID()); - requisitionService.reject(requisition, emptyMap(), generateRejections()); + requisitionService.reject(requisition, emptyMap(), generateRejections(), + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); } @Test @@ -500,7 +507,8 @@ public void shouldSaveStatusMessageWhileRejectingRequisition() { any(UUID.class), any(UUID.class), any(UUID.class), any(UUID.class))) .thenReturn(true); Requisition returnedRequisition = requisitionService.reject(requisition, orderables, - generateRejections()); + generateRejections(), mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); assertEquals(returnedRequisition.getStatus(), REJECTED); verify(statusMessageRepository, times(1)).save(any(StatusMessage.class)); } @@ -514,7 +522,8 @@ public void shouldSetNullToSupervisoryNodeWhileRejectingRequisition() { any(UUID.class), any(UUID.class), any(UUID.class),any(UUID.class))) .thenReturn(true); Requisition returnedRequisition = requisitionService.reject(requisition, orderables, - generateRejections()); + generateRejections(), mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); assertEquals(returnedRequisition.getStatus(), REJECTED); assertNull(returnedRequisition.getSupervisoryNodeId()); } @@ -523,14 +532,18 @@ public void shouldSetNullToSupervisoryNodeWhileRejectingRequisition() { public void shouldThrowExceptionWhenRejectingRequisitionWithStatusSubmitted() throws ValidationMessageException { requisition.setStatus(SUBMITTED); - requisitionService.reject(requisition, emptyMap(), generateRejections()); + requisitionService.reject(requisition, emptyMap(), generateRejections(), + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); } @Test(expected = ValidationMessageException.class) public void shouldThrowExceptionWhenRejectingRequisitionWithStatusApproved() throws ValidationMessageException { requisition.setStatus(APPROVED); - requisitionService.reject(requisition, emptyMap(), generateRejections()); + requisitionService.reject(requisition, emptyMap(), generateRejections(), + mock(ProcessingPeriodDto.class), mock(RequisitionService.class), + mock(PeriodService.class), mock(Profiler.class)); } @Test @@ -1268,12 +1281,14 @@ public void shouldCallApproveRequisition() { requisitionService.doApprove( parentId, user, ImmutableMap.of(fullSupplyOrderable.getIdentity(), fullSupplyOrderable), - requisitionMock, singletonList(supplyLineDto) + requisitionMock, singletonList(supplyLineDto), mock(ProcessingPeriodDto.class), + mock(Profiler.class) ); verify(requisitionMock, times(1)).approve(eq(parentId), eq(ImmutableMap.of(fullSupplyOrderable.getIdentity(), fullSupplyOrderable)), - eq(singletonList(supplyLineDto)), eq(user.getId())); + eq(singletonList(supplyLineDto)), eq(user.getId()), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class)); } @Test diff --git a/src/test/java/org/openlmis/requisition/testutils/StockCardRangeSummaryDtoDataBuilder.java b/src/test/java/org/openlmis/requisition/testutils/StockCardRangeSummaryDtoDataBuilder.java index 3344442b8..908365496 100644 --- a/src/test/java/org/openlmis/requisition/testutils/StockCardRangeSummaryDtoDataBuilder.java +++ b/src/test/java/org/openlmis/requisition/testutils/StockCardRangeSummaryDtoDataBuilder.java @@ -58,6 +58,11 @@ public StockCardRangeSummaryDtoDataBuilder withStockOutDays(Integer stockOutDays return this; } + public StockCardRangeSummaryDtoDataBuilder withAmount(Integer amount) { + this.amount = amount; + return this; + } + /** * Sets orderable reference object with given id. */ diff --git a/src/test/java/org/openlmis/requisition/validate/RequisitionValidationTestUtils.java b/src/test/java/org/openlmis/requisition/validate/RequisitionValidationTestUtils.java index 8e5365a5a..95ec16e74 100644 --- a/src/test/java/org/openlmis/requisition/validate/RequisitionValidationTestUtils.java +++ b/src/test/java/org/openlmis/requisition/validate/RequisitionValidationTestUtils.java @@ -18,6 +18,7 @@ import static org.openlmis.requisition.domain.SourceType.CALCULATED; import static org.openlmis.requisition.domain.SourceType.USER_INPUT; import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.ADDITIONAL_QUANTITY_REQUIRED; +import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.ADJUSTED_CONSUMPTION; import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.APPROVED_QUANTITY; import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.AVERAGE_CONSUMPTION; import static org.openlmis.requisition.domain.requisition.RequisitionLineItem.BEGINNING_BALANCE; @@ -123,6 +124,9 @@ public static Map initiateColumns() { AVERAGE_CONSUMPTION, generateTemplateColumn(AVERAGE_CONSUMPTION, "P", CALCULATED) ); + columns.put( + ADJUSTED_CONSUMPTION, generateTemplateColumn(ADJUSTED_CONSUMPTION, "N", CALCULATED) + ); columns.put(NUMBER_OF_PATIENTS_ON_TREATMENT_NEXT_MONTH, generateTemplateColumn(NUMBER_OF_PATIENTS_ON_TREATMENT_NEXT_MONTH, "TC", CALCULATED) ); diff --git a/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java b/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java index 6d5186f4c..841f2d5b1 100644 --- a/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java +++ b/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java @@ -25,6 +25,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyCollection; @@ -253,13 +254,13 @@ public class RequisitionControllerTest { @Mock private HttpServletRequest request; - + @Mock private ValidReasonStockmanagementService validReasonStockmanagementService; - + @Mock private ReasonsValidator reasonsValidator; - + @Mock private RequisitionTemplateService requisitionTemplateService; @@ -415,10 +416,12 @@ public void shouldSubmitValidInitiatedRequisition() { mockDependenciesForSubmit(); requisitionController.submitRequisition(uuid1, request, response); - verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false)); + verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); // we do not update in this endpoint verify(initiatedRequsition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + any(Requisition.class), anyMap(), anyMap(), anyBoolean(), isNull(), isNull()); verify(initiatedRequsition) .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), true, Maps.newHashMap(), Maps.newHashMap()); @@ -432,10 +435,12 @@ public void shouldDirectlyAuthorizeInitiatedRequisitionIfAuthorizeStepSkipped() requisitionController.submitRequisition(uuid1, request, response); - verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(true)); + verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(true), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); // we do not update in this endpoint - verify(initiatedRequsition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + verify(initiatedRequsition, never()).updateFrom(any(Requisition.class), anyMap(), anyMap(), + anyBoolean(), any(RequisitionService.class), any(PeriodService.class)); } @Test @@ -448,10 +453,12 @@ public void shouldSubmitEmergencyRequisitionForAnyPeriod() { requisitionController.submitRequisition(uuid1, request, response); - verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false)); + verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); // we do not update in this endpoint verify(initiatedRequsition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + any(Requisition.class), anyMap(), anyMap(), anyBoolean(), isNull(), isNull()); verify(initiatedRequsition) .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), true, Maps.newHashMap(), Maps.newHashMap()); @@ -467,10 +474,12 @@ public void shouldRejectSubmitRegularRequisitionForWrongPeriod() { requisitionController.submitRequisition(uuid1, request, response); - verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false)); + verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); // we do not update in this endpoint verify(initiatedRequsition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + any(Requisition.class), anyMap(), anyMap(), anyBoolean(), null, null); } @Test @@ -479,10 +488,12 @@ public void shouldSubmitRequisitionWithIdempotencyKey() { when(request.getHeader(IDEMPOTENCY_KEY_HEADER)).thenReturn(key.toString()); requisitionController.submitRequisition(uuid1, request, response); - verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false)); + verify(initiatedRequsition).submit(eq(Collections.emptyMap()), any(UUID.class), eq(false), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); // we do not update in this endpoint verify(initiatedRequsition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + any(Requisition.class), anyMap(), anyMap(), anyBoolean(), isNull(), isNull()); verify(initiatedRequsition) .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), true, Maps.newHashMap(), Maps.newHashMap()); @@ -594,10 +605,10 @@ public void shouldUpdateRequisition() { assertEquals(template, initiatedRequsition.getTemplate()); verify(initiatedRequsition).updateFrom( - any(Requisition.class), anyMap(), anyMap(), eq(true)); + any(Requisition.class), anyMap(), anyMap(), eq(true), isNull(), isNull()); verify(requisitionRepository).save(initiatedRequsition); - verify(requisitionVersionValidator).validateEtagVersionIfPresent(any(HttpServletRequest.class), - eq(initiatedRequsition)); + verify(requisitionVersionValidator).validateEtagVersionIfPresent( + any(HttpServletRequest.class), eq(initiatedRequsition)); verifySupervisoryNodeWasNotUpdated(initiatedRequsition); } @@ -640,10 +651,10 @@ public void shouldUpdateStockBasedRequisition() { assertEquals(template, initiatedRequsition.getTemplate()); verify(initiatedRequsition).updateFrom( - any(Requisition.class), anyMap(), anyMap(), eq(true)); + any(Requisition.class), anyMap(), anyMap(), eq(true), isNull(), isNull()); verify(requisitionRepository).save(initiatedRequsition); - verify(requisitionVersionValidator).validateEtagVersionIfPresent(any(HttpServletRequest.class), - eq(initiatedRequsition)); + verify(requisitionVersionValidator).validateEtagVersionIfPresent( + any(HttpServletRequest.class), eq(initiatedRequsition)); verifySupervisoryNodeWasNotUpdated(initiatedRequsition); } @@ -843,8 +854,9 @@ public void shouldApproveAuthorizedRequisitionWithParentNode() { any(Requisition.class), any(UUID.class)); - verify(requisitionService, times(1)).doApprove(eq(parentNodeId), any(), - any(), eq(authorizedRequsition), eq(emptyList())); + verify(requisitionService, times(1)).doApprove(eq(parentNodeId), any(), any(), + eq(authorizedRequsition), eq(emptyList()), any(ProcessingPeriodDto.class), + any(Profiler.class)); verifyZeroInteractions(stockEventBuilderBuilder, stockEventService); verify(authorizedRequsition) @@ -883,10 +895,12 @@ public void shouldApproveSplittableRequisition() { verify(requisitionService) .validateCanApproveRequisition(any(Requisition.class), any(UUID.class)); - verify(requisitionService).doApprove(eq(parentNodeId), any(), - any(), eq(authorizedRequsition), eq(emptyList())); + verify(requisitionService).doApprove(eq(parentNodeId), any(), any(), + eq(authorizedRequsition), eq(emptyList()), any(ProcessingPeriodDto.class), + any(Profiler.class)); verify(requisitionService).doApprove(eq(partnerNode.getParentNodeId()), any(), - any(), eq(partnerRequisition), eq(emptyList())); + any(), eq(partnerRequisition), eq(emptyList()), any(ProcessingPeriodDto.class), + any(Profiler.class)); verifyZeroInteractions(stockEventBuilderBuilder, stockEventService); verify(authorizedRequsition) @@ -915,8 +929,8 @@ public void shouldApproveAuthorizedRequisitionWithParentNodeAndWithoutSupplyLine any(Requisition.class), any(UUID.class)); - verify(requisitionService, times(1)).doApprove(eq(parentNodeId), any(), - any(), eq(authorizedRequsition), eq(null)); + verify(requisitionService, times(1)).doApprove(eq(parentNodeId), any(), any(), + eq(authorizedRequsition), eq(null), any(ProcessingPeriodDto.class), any(Profiler.class)); verifyZeroInteractions(stockEventBuilderBuilder, stockEventService); verify(authorizedRequsition) @@ -941,8 +955,9 @@ public void shouldApproveAuthorizedRequisitionWithParentNodeAndSupplyLineForProg any(Requisition.class), any(UUID.class)); - verify(requisitionService, times(1)).doApprove(eq(parentNodeId), any(), - any(), eq(authorizedRequsition), eq(singletonList(supplyLineDto))); + verify(requisitionService, times(1)).doApprove(eq(parentNodeId), any(), any(), + eq(authorizedRequsition), eq(singletonList(supplyLineDto)), + any(ProcessingPeriodDto.class), any(Profiler.class)); verify(authorizedRequsition) .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), true, Maps.newHashMap(), Maps.newHashMap()); @@ -965,8 +980,9 @@ public void shouldApproveAuthorizedRequisitionWithoutParentNode() { verify(stockEventBuilderBuilder).fromRequisition(authorizedRequsition, currentUser.getId(), Maps.newHashMap()); verify(stockEventService).submit(stockEventDto); - verify(requisitionService, times(1)).doApprove(eq(null), any(), - any(), eq(authorizedRequsition), eq(singletonList(supplyLineDto))); + verify(requisitionService, times(1)).doApprove(eq(null), any(), any(), + eq(authorizedRequsition), eq(singletonList(supplyLineDto)), any(ProcessingPeriodDto.class), + any(Profiler.class)); verify(authorizedRequsition) .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), true, Maps.newHashMap(), Maps.newHashMap()); @@ -984,8 +1000,9 @@ public void shouldNotSendStockEventOnFinalApprovalForEmergencyRequisition() { any(UUID.class)); verifyZeroInteractions(stockEventBuilderBuilder, stockEventService); - verify(requisitionService, times(1)).doApprove(eq(null), any(), - any(), eq(authorizedRequsition), eq(singletonList(supplyLineDto))); + verify(requisitionService, times(1)).doApprove(eq(null), any(), any(), + eq(authorizedRequsition), eq(singletonList(supplyLineDto)), + any(ProcessingPeriodDto.class), any(Profiler.class)); verify(authorizedRequsition) .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), true, Maps.newHashMap(), Maps.newHashMap()); @@ -1003,8 +1020,9 @@ public void shouldNotSendStockEventWhenRequisitionIsConfiguredToPullFromStockCar any(UUID.class)); verifyZeroInteractions(stockEventBuilderBuilder, stockEventService); - verify(requisitionService, times(1)).doApprove(eq(null), any(), - any(), eq(authorizedRequsition), eq(singletonList(supplyLineDto))); + verify(requisitionService, times(1)).doApprove(eq(null), any(), any(), + eq(authorizedRequsition), eq(singletonList(supplyLineDto)), + any(ProcessingPeriodDto.class), any(Profiler.class)); verify(authorizedRequsition) .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), true, Maps.newHashMap(), Maps.newHashMap()); @@ -1068,15 +1086,17 @@ public void shouldNotApproveIfHasNoPermission() { public void shouldRejectRequisitionWhenUserCanApproveRequisition() { when(permissionService.canApproveRequisition(authorizedRequsition)) .thenReturn(ValidationResult.success()); - when(requisitionService.reject(authorizedRequsition, Collections.emptyMap(), - generateRejections())) + when(requisitionService.reject(eq(authorizedRequsition), eq(Collections.emptyMap()), + eq(generateRejections()), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class))) .thenReturn(initiatedRequsition); requisitionController.rejectRequisition(authorizedRequsition.getId(), request, response, - generateRejections()); + generateRejections()); - verify(requisitionService, times(1)).reject(authorizedRequsition, - Collections.emptyMap(), generateRejections()); + verify(requisitionService, times(1)).reject(eq(authorizedRequsition), + eq(Collections.emptyMap()), eq(generateRejections()), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class)); } @Test @@ -1089,16 +1109,18 @@ public void shouldNotRejectRequisitionWhenUserCanNotApproveRequisition() { response, generateRejections())) .isInstanceOf(PermissionMessageException.class); - verify(requisitionService, times(0)).reject(authorizedRequsition, - Collections.emptyMap(), generateRejections()); + verify(requisitionService, times(0)).reject(eq(authorizedRequsition), + eq(Collections.emptyMap()), eq(generateRejections()), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class)); } @Test public void shouldRejectRequisitionWithIdempotencyKey() { when(permissionService.canApproveRequisition(authorizedRequsition)) .thenReturn(ValidationResult.success()); - when(requisitionService.reject(authorizedRequsition, Collections.emptyMap(), - generateRejections())) + when(requisitionService.reject(eq(authorizedRequsition), eq(emptyMap()), + eq(generateRejections()), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class))) .thenReturn(initiatedRequsition); when(request.getHeader(IDEMPOTENCY_KEY_HEADER)).thenReturn(key.toString()); @@ -1118,8 +1140,9 @@ public void shouldNotRejectRequisitionIfIdempotencyKeyHasWrongFormat() { when(permissionService.canApproveRequisition(authorizedRequsition)) .thenReturn(ValidationResult.success()); - when(requisitionService.reject(authorizedRequsition, Collections.emptyMap(), - generateRejections())) + when(requisitionService.reject(eq(authorizedRequsition), eq(Collections.emptyMap()), + eq(generateRejections()), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class))) .thenReturn(initiatedRequsition); when(request.getHeader(IDEMPOTENCY_KEY_HEADER)).thenReturn(wrongUuidFormat); @@ -1135,7 +1158,8 @@ public void shouldNotRejectRequisitionWithUsedIdempotencyKey() { when(permissionService.canApproveRequisition(authorizedRequsition)) .thenReturn(ValidationResult.success()); when(requisitionService.reject(authorizedRequsition, Collections.emptyMap(), - generateRejections())) + generateRejections(), mock(ProcessingPeriodDto.class), + mock(RequisitionService.class), mock(PeriodService.class), mock(Profiler.class))) .thenReturn(initiatedRequsition); when(request.getHeader(IDEMPOTENCY_KEY_HEADER)).thenReturn(key.toString()); when(processedRequestsRedisRepository.exists(key)).thenReturn(true); @@ -1148,8 +1172,9 @@ public void shouldNotRejectRequisitionWithUsedIdempotencyKey() { public void shouldCallRequisitionStatusNotifierWhenReject() { when(permissionService.canApproveRequisition(authorizedRequsition)) .thenReturn(ValidationResult.success()); - when(requisitionService.reject(authorizedRequsition, Collections.emptyMap(), - generateRejections())) + when(requisitionService.reject(eq(authorizedRequsition), eq(Collections.emptyMap()), + eq(generateRejections()), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class))) .thenReturn(initiatedRequsition); requisitionController.rejectRequisition(authorizedRequsition.getId(), request, @@ -1180,6 +1205,10 @@ public void shouldAuthorizeRequisitionWithIdempotencyKey() { when(request.getHeader(IDEMPOTENCY_KEY_HEADER)).thenReturn(key.toString()); setUpAuthorizer(); + RequisitionTemplate newTemplate = mock(RequisitionTemplate.class); + when(submittedRequsition.getTemplate()).thenReturn(newTemplate); + when(newTemplate.isPopulateStockOnHandFromStockCards()).thenReturn(false); + requisitionController.authorizeRequisition(submittedRequsition.getId(), request, response); verify(response, times(1)).addHeader( @@ -1215,6 +1244,10 @@ public void shouldNotAuthorizeRequisitionWithUsedIdempotencyKey() { public void shouldProcessStatusChangeWhenAuthorizingRequisition() { setUpAuthorizer(); + RequisitionTemplate newTemplate = mock(RequisitionTemplate.class); + when(submittedRequsition.getTemplate()).thenReturn(newTemplate); + when(newTemplate.isPopulateStockOnHandFromStockCards()).thenReturn(false); + requisitionController.authorizeRequisition(submittedRequsition.getId(), request, response); verify(requisitionStatusProcessor) @@ -1225,6 +1258,10 @@ public void shouldProcessStatusChangeWhenAuthorizingRequisition() { public void shouldCallValidationsWhenAuthorizingRequisition() { setUpAuthorizer(); + RequisitionTemplate newTemplate = mock(RequisitionTemplate.class); + when(submittedRequsition.getTemplate()).thenReturn(newTemplate); + when(newTemplate.isPopulateStockOnHandFromStockCards()).thenReturn(false); + requisitionController.authorizeRequisition(submittedRequsition.getId(), request, response); verify(submittedRequsition) @@ -1240,7 +1277,8 @@ public void shouldNotAuthorizeInvalidRequisition() { .validateCanChangeStatus(any(LocalDate.class), anyBoolean(), anyMap(), anyMap()); assertThatThrownBy(() -> - requisitionController.authorizeRequisition(submittedRequsition.getId(), request, response)) + requisitionController.authorizeRequisition(submittedRequsition.getId(), + request, response)) .isInstanceOf(BindingResultException.class) .hasMessage(bindingResultMessage); @@ -1430,26 +1468,30 @@ private void mockRequisitionRepository() { private void verifyNoSubmitOrUpdate(Requisition requisition) { verifyNoMoreInteractions(requisitionService); - verify(requisition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + verify(requisition, never()).updateFrom(any(Requisition.class), anyMap(), anyMap(), + anyBoolean(), any(RequisitionService.class), any(PeriodService.class)); verify(requisition, never()).validateCanBeUpdated(any(RequisitionValidationService.class)); - verify(requisition, never()).submit(eq(emptyMap()), any(UUID.class), anyBoolean()); + verify(requisition, never()).submit(eq(emptyMap()), any(UUID.class), anyBoolean(), + any(ProcessingPeriodDto.class), any(RequisitionService.class), any(PeriodService.class), + any(Profiler.class)); } private void verifyNoApproveOrUpdate(Requisition requisition) { - verify(requisition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + verify(requisition, never()).updateFrom(any(Requisition.class), anyMap(), anyMap(), + anyBoolean(), any(RequisitionService.class), any(PeriodService.class)); verify(requisition, never()).validateCanBeUpdated(any(RequisitionValidationService.class)); - verify(requisition, never()) - .approve(any(UUID.class), anyMap(), anyCollection(), any(UUID.class)); + verify(requisition, never()).approve(any(UUID.class), anyMap(), anyCollection(), + any(UUID.class), any(ProcessingPeriodDto.class), any(RequisitionService.class), + any(PeriodService.class), any(Profiler.class)); } private void verifyNoAuthorizeOrUpdate(Requisition requisition) { - verify(requisition, never()).updateFrom( - any(Requisition.class), anyMap(), anyMap(), anyBoolean()); + verify(requisition, never()).updateFrom(any(Requisition.class), anyMap(), anyMap(), + anyBoolean(), any(RequisitionService.class), any(PeriodService.class)); verify(requisition, never()).validateCanBeUpdated(any(RequisitionValidationService.class)); verify(requisition, never()) - .authorize(anyMap(), any(UUID.class)); + .authorize(anyMap(), any(UUID.class), any(ProcessingPeriodDto.class), + any(RequisitionService.class), any(PeriodService.class), any(Profiler.class)); } private void verifySupervisoryNodeWasNotUpdated(Requisition requisition) {