From b22159c5177a9d1506924e66a645bb8068af30d7 Mon Sep 17 00:00:00 2001 From: druchniewicz Date: Wed, 19 Feb 2025 13:48:28 +0100 Subject: [PATCH 1/3] OPSD-13: Made transferring stock data from requisition to stock management configurable --- .../web/RequisitionController.java | 7 ++- src/main/resources/application.properties | 4 +- .../web/RequisitionControllerTest.java | 49 ++++++++++++++----- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/openlmis/requisition/web/RequisitionController.java b/src/main/java/org/openlmis/requisition/web/RequisitionController.java index 5d9099429..9dfa7c8f9 100644 --- a/src/main/java/org/openlmis/requisition/web/RequisitionController.java +++ b/src/main/java/org/openlmis/requisition/web/RequisitionController.java @@ -56,6 +56,7 @@ import org.openlmis.requisition.utils.Pagination; import org.slf4j.profiler.Profiler; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -88,6 +89,9 @@ public class RequisitionController extends BaseRequisitionController { @Autowired private SupervisoryNodeReferenceDataService supervisoryNodeService; + @Value("${transferDataToStockManagement.enabled}") + private boolean isTransferStockDataFromRequisitionToStockManagementEnabled; + /** * Allows creating new requisitions. * @@ -457,7 +461,8 @@ public BasicRequisitionDto approveRequisition( BasicRequisitionDto requisitionDto = buildBasicDto(profiler, requisition); RequisitionTemplate requisitionTemplate = requisition.getTemplate(); if (!requisitionTemplate.isPopulateStockOnHandFromStockCards() - && !requisitionTemplate.isPatientsTabEnabled()) { + && !requisitionTemplate.isPatientsTabEnabled() + && isTransferStockDataFromRequisitionToStockManagementEnabled) { submitStockEvent(requisition, user.getId(), orderables); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 220b40844..11725e680 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -81,4 +81,6 @@ spring.data.rest.maxPageSize=2147483647 #why 2000 ? Check https://stackoverflow.com/a/417184 request.maxUrlLength=2000 -unskip.requisition.item.when.approving=${UNSKIP_REQUISITION_ITEM_WHEN_APPROVING:false} \ No newline at end of file +unskip.requisition.item.when.approving=${UNSKIP_REQUISITION_ITEM_WHEN_APPROVING:false} + +transferDataToStockManagement.enabled=${TRANSFER_DATA_TO_STOCK_MANAGEMENT:true} \ No newline at end of file diff --git a/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java b/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java index b3358cb2e..8f587049b 100644 --- a/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java +++ b/src/test/java/org/openlmis/requisition/web/RequisitionControllerTest.java @@ -43,6 +43,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @@ -965,28 +966,52 @@ public void shouldApproveAuthorizedRequisitionWithParentNodeAndSupplyLineForProg } @Test - public void shouldApproveAuthorizedRequisitionWithoutParentNode() { + public void shouldApproveAuthorizedRequisitionWithoutParentNodeWhenTransferStockDataIsEnabled() { + ReflectionTestUtils.setField(requisitionController, + "isTransferStockDataFromRequisitionToStockManagementEnabled", true); final SupplyLineDto supplyLineDto = prepareForApproveWithSupplyLine(); when(authorizedRequsition.getEmergency()).thenReturn(false); StockEventDto stockEventDto = DtoGenerator.of(StockEventDto.class); when(stockEventBuilderBuilder.fromRequisition(any(Requisition.class), any(), anyMap())) - .thenReturn(stockEventDto); + .thenReturn(stockEventDto); requisitionController.approveRequisition(authorizedRequsition.getId(), request, response); - verify(requisitionService, times(1)).validateCanApproveRequisition( - any(Requisition.class), - any(UUID.class)); - + verify(requisitionService).validateCanApproveRequisition( + any(Requisition.class), + any(UUID.class)); + verify(authorizedRequsition) + .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), + true, Maps.newHashMap(), Maps.newHashMap()); + verify(requisitionService).doApprove(eq(null), any(), any(), eq(authorizedRequsition), + eq(singletonList(supplyLineDto)), any(ProcessingPeriodDto.class), any(Profiler.class)); verify(stockEventBuilderBuilder).fromRequisition(authorizedRequsition, - currentUser.getId(), Maps.newHashMap()); + currentUser.getId(), Maps.newHashMap()); verify(stockEventService).submit(stockEventDto); - verify(requisitionService, times(1)).doApprove(eq(null), any(), any(), - eq(authorizedRequsition), eq(singletonList(supplyLineDto)), any(ProcessingPeriodDto.class), - any(Profiler.class)); + } + + @Test + public void shouldApproveAuthorizedRequisitionWithoutParentNodeWhenTransferStockDataIsDisabled() { + ReflectionTestUtils.setField(requisitionController, + "isTransferStockDataFromRequisitionToStockManagementEnabled", false); + final SupplyLineDto supplyLineDto = prepareForApproveWithSupplyLine(); + when(authorizedRequsition.getEmergency()).thenReturn(false); + StockEventDto stockEventDto = DtoGenerator.of(StockEventDto.class); + when(stockEventBuilderBuilder.fromRequisition(any(Requisition.class), any(), anyMap())) + .thenReturn(stockEventDto); + + requisitionController.approveRequisition(authorizedRequsition.getId(), request, response); + + verify(requisitionService).validateCanApproveRequisition( + any(Requisition.class), + any(UUID.class)); verify(authorizedRequsition) - .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), - true, Maps.newHashMap(), Maps.newHashMap()); + .validateCanChangeStatus(dateHelper.getCurrentDateWithSystemZone(), + true, Maps.newHashMap(), Maps.newHashMap()); + verify(requisitionService).doApprove(eq(null), any(), + any(), eq(authorizedRequsition), eq(singletonList(supplyLineDto)), + any(ProcessingPeriodDto.class), any(Profiler.class)); + verifyNoInteractions(stockEventBuilderBuilder, stockEventService); } @Test From f6bbf8e4c08e988d3c31d4ad1cf4bd7040f536e7 Mon Sep 17 00:00:00 2001 From: druchniewicz Date: Thu, 20 Feb 2025 16:32:11 +0100 Subject: [PATCH 2/3] OPSD-13: Submitting stock event in batch requisition controller only if feature flag enabled --- .../requisition/web/BatchRequisitionController.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openlmis/requisition/web/BatchRequisitionController.java b/src/main/java/org/openlmis/requisition/web/BatchRequisitionController.java index 8334b3723..68898199e 100644 --- a/src/main/java/org/openlmis/requisition/web/BatchRequisitionController.java +++ b/src/main/java/org/openlmis/requisition/web/BatchRequisitionController.java @@ -75,6 +75,7 @@ import org.slf4j.ext.XLoggerFactory; import org.slf4j.profiler.Profiler; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -107,6 +108,9 @@ public class BatchRequisitionController extends BaseRequisitionController { @Autowired private PeriodReferenceDataService periodReferenceDataService; + @Value("${transferDataToStockManagement.enabled}") + private boolean isTransferStockDataFromRequisitionToStockManagementEnabled; + /** * Attempts to retrieve requisitions with the provided UUIDs. */ @@ -210,7 +214,9 @@ public ResponseEntity approve( facilities, periods, approveParams, approvedProducts); } - submitStockEvent(profiler, user, requisitions, orderables); + if (isTransferStockDataFromRequisitionToStockManagementEnabled) { + submitStockEvent(profiler, user, requisitions, orderables); + } ResponseEntity response = buildResponse(processingStatus, profiler, HttpStatus.OK); From 2becb815b6914274f1ef4801c5c58b649c645bb6 Mon Sep 17 00:00:00 2001 From: druchniewicz Date: Thu, 20 Feb 2025 21:00:31 +0100 Subject: [PATCH 3/3] OPSD-13: Added tests for last changes --- .../web/BatchRequisitionControllerTest.java | 120 +++++++++++++++++- 1 file changed, 118 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/openlmis/requisition/web/BatchRequisitionControllerTest.java b/src/test/java/org/openlmis/requisition/web/BatchRequisitionControllerTest.java index 9c0773f53..b4def08ce 100644 --- a/src/test/java/org/openlmis/requisition/web/BatchRequisitionControllerTest.java +++ b/src/test/java/org/openlmis/requisition/web/BatchRequisitionControllerTest.java @@ -15,28 +15,52 @@ package org.openlmis.requisition.web; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyList; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.atLeastOnce; +import com.google.common.collect.Maps; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.UUID; + import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.openlmis.requisition.domain.requisition.Requisition; +import org.openlmis.requisition.domain.requisition.RequisitionStatus; import org.openlmis.requisition.dto.ReleasableRequisitionBatchDto; import org.openlmis.requisition.dto.UserDto; +import org.openlmis.requisition.dto.stockmanagement.StockEventDto; import org.openlmis.requisition.errorhandling.ValidationResult; +import org.openlmis.requisition.i18n.MessageService; +import org.openlmis.requisition.repository.RequisitionRepository; import org.openlmis.requisition.service.PermissionService; import org.openlmis.requisition.service.RequisitionService; +import org.openlmis.requisition.service.referencedata.FacilityReferenceDataService; +import org.openlmis.requisition.service.referencedata.FacilityTypeApprovedProductReferenceDataService; +import org.openlmis.requisition.service.referencedata.OrderableReferenceDataService; +import org.openlmis.requisition.service.referencedata.PeriodReferenceDataService; +import org.openlmis.requisition.service.referencedata.SupervisoryNodeReferenceDataService; +import org.openlmis.requisition.service.referencedata.SupplyLineReferenceDataService; +import org.openlmis.requisition.service.referencedata.UserReferenceDataService; +import org.openlmis.requisition.service.stockmanagement.StockEventStockManagementService; import org.openlmis.requisition.testutils.DtoGenerator; import org.openlmis.requisition.testutils.ReleasableRequisitionBatchDtoDataBuilder; import org.openlmis.requisition.utils.AuthenticationHelper; +import org.openlmis.requisition.utils.StockEventBuilder; +import org.springframework.test.util.ReflectionTestUtils; public class BatchRequisitionControllerTest { @@ -49,14 +73,56 @@ public class BatchRequisitionControllerTest { @Mock PermissionService permissionService; + @Mock + RequisitionRepository requisitionRepository; + + @Mock + UserReferenceDataService userReferenceDataService; + + @Mock + SupervisoryNodeReferenceDataService supervisoryNodeReferenceDataService; + + @Mock + OrderableReferenceDataService orderableReferenceDataService; + + @Mock + FacilityReferenceDataService facilityReferenceDataService; + + @Mock + PeriodReferenceDataService periodReferenceDataService; + + @Mock + FacilityTypeApprovedProductReferenceDataService facilityTypeApprovedService; + + @Mock + SupplyLineReferenceDataService supplyLineReferenceDataService; + + @Mock + MessageService messageService; + + @Mock + StockEventBuilder stockEventBuilder; + + @Mock + StockEventStockManagementService stockEventStockManagementService; + + @Mock + Requisition requisition; + @InjectMocks - BatchRequisitionController batchRequisitionController; + private BatchRequisitionController batchRequisitionController; + + private final UUID uuid1 = UUID.fromString("00000000-0000-0000-0000-000000000001"); + + private final UUID uuid2 = UUID.fromString("00000000-0000-0000-0000-000000000002"); + + private UserDto currentUser; @Before public void setUp() { MockitoAnnotations.initMocks(this); - UserDto currentUser = DtoGenerator.of(UserDto.class); + currentUser = DtoGenerator.of(UserDto.class); when(authenticationHelper.getCurrentUser()).thenReturn(currentUser); } @@ -98,4 +164,54 @@ public void batchReleaseRequisitionsWithoutOrderWhenUserHasPermission() { verify(requisitionService, atLeastOnce()).releaseWithoutOrder(any()); } + @Test + public void approveMultipleRequisitionsWhenTransferStockDataIsEnabled() { + ReflectionTestUtils.setField(batchRequisitionController, + "isTransferStockDataFromRequisitionToStockManagementEnabled", true); + when(requisitionRepository.readDistinctByIdIn(anyList())) + .thenReturn(Collections.singletonList(requisition)); + when(requisition.getStatus()).thenReturn(RequisitionStatus.APPROVED); + + StockEventDto stockEventDto = DtoGenerator.of(StockEventDto.class); + when(stockEventBuilder.fromRequisition(any(Requisition.class), any(), anyMap())) + .thenReturn(stockEventDto); + + batchRequisitionController.approve(Arrays.asList(uuid1, uuid2)); + + verify(authenticationHelper).getCurrentUser(); + verify(requisitionRepository).readDistinctByIdIn(anyCollection()); + verify(userReferenceDataService).getPermissionStrings(currentUser.getId()); + verify(supervisoryNodeReferenceDataService).findByIds(anyList()); + verify(orderableReferenceDataService).findByIdentities(anySet()); + verify(facilityReferenceDataService).search(anySet()); + verify(periodReferenceDataService).search(anySet()); + verify(facilityTypeApprovedService).findByIdentities(anySet()); + verify(stockEventBuilder).fromRequisition(requisition, currentUser.getId(), Maps.newHashMap()); + verify(stockEventStockManagementService).submit(stockEventDto); + } + + @Test + public void approveMultipleRequisitionsWhenTransferStockDataIsDisabled() { + ReflectionTestUtils.setField(batchRequisitionController, + "isTransferStockDataFromRequisitionToStockManagementEnabled", false); + when(requisitionRepository.readDistinctByIdIn(anyList())) + .thenReturn(Collections.singletonList(requisition)); + when(requisition.getStatus()).thenReturn(RequisitionStatus.APPROVED); + + StockEventDto stockEventDto = DtoGenerator.of(StockEventDto.class); + when(stockEventBuilder.fromRequisition(any(Requisition.class), any(), anyMap())) + .thenReturn(stockEventDto); + + batchRequisitionController.approve(Arrays.asList(uuid1, uuid2)); + + verify(authenticationHelper).getCurrentUser(); + verify(requisitionRepository).readDistinctByIdIn(anyCollection()); + verify(userReferenceDataService).getPermissionStrings(currentUser.getId()); + verify(supervisoryNodeReferenceDataService).findByIds(anyList()); + verify(orderableReferenceDataService).findByIdentities(anySet()); + verify(facilityReferenceDataService).search(anySet()); + verify(periodReferenceDataService).search(anySet()); + verify(facilityTypeApprovedService).findByIdentities(anySet()); + verifyNoInteractions(stockEventBuilder, stockEventStockManagementService); + } } \ No newline at end of file