diff --git a/src/main/java/org/folio/dcb/listener/kafka/CirculationEventListener.java b/src/main/java/org/folio/dcb/listener/kafka/CirculationEventListener.java index 85e80095..947fa2c5 100644 --- a/src/main/java/org/folio/dcb/listener/kafka/CirculationEventListener.java +++ b/src/main/java/org/folio/dcb/listener/kafka/CirculationEventListener.java @@ -78,7 +78,7 @@ public void handleRequestEvent(String data, MessageHeaders messageHeaders) { systemUserScopedExecutionService.executeAsyncSystemUserScoped(tenantId, () -> transactionRepository.findTransactionByRequestIdAndStatusNotInClosed(UUID.fromString(requestId)) .ifPresent(transactionEntity -> { - if (eventData.getType() == EventData.EventType.CANCEL) { + if (eventData.getType() == EventData.EventType.CANCEL && !eventData.isDcbReRequestCancellation()) { baseLibraryService.cancelTransactionEntity(transactionEntity); } else if (eventData.getType() == EventData.EventType.IN_TRANSIT && transactionEntity.getRole() == LENDER) { baseLibraryService.updateTransactionEntity(transactionEntity, TransactionStatus.StatusEnum.OPEN); diff --git a/src/main/java/org/folio/dcb/listener/kafka/EventData.java b/src/main/java/org/folio/dcb/listener/kafka/EventData.java index 0b786a2b..4f7779ec 100644 --- a/src/main/java/org/folio/dcb/listener/kafka/EventData.java +++ b/src/main/java/org/folio/dcb/listener/kafka/EventData.java @@ -8,6 +8,7 @@ public class EventData { private String itemId; private String requestId; private boolean isDcb; + private boolean isDcbReRequestCancellation; public enum EventType { CHECK_IN, CHECK_OUT, IN_TRANSIT, AWAITING_PICKUP, CANCEL diff --git a/src/main/java/org/folio/dcb/service/impl/CirculationServiceImpl.java b/src/main/java/org/folio/dcb/service/impl/CirculationServiceImpl.java index b4110b26..b0159392 100644 --- a/src/main/java/org/folio/dcb/service/impl/CirculationServiceImpl.java +++ b/src/main/java/org/folio/dcb/service/impl/CirculationServiceImpl.java @@ -47,7 +47,7 @@ public void cancelRequest(TransactionEntity dcbTransaction, boolean isItemUnavai if (request != null){ try { if (isItemUnavailableCancellation) { - request.setIsSuppressNotification(true); + request.setIsDcbReRequestCancellation(true); } circulationClient.updateRequest(request.getId(), request); } catch (FeignException e) { diff --git a/src/main/java/org/folio/dcb/utils/DCBConstants.java b/src/main/java/org/folio/dcb/utils/DCBConstants.java index e650dcb8..12bca85e 100644 --- a/src/main/java/org/folio/dcb/utils/DCBConstants.java +++ b/src/main/java/org/folio/dcb/utils/DCBConstants.java @@ -26,5 +26,4 @@ private DCBConstants() {} public static final String SHADOW_TYPE = "shadow"; public static final String HOLDING_SOURCE = "folio"; public static final String DCB_CALENDAR_NAME = "DCB Calendar"; - public static final String ITEM_UNAVAILABLE_CANCELLATION_MSG = "Request cancelled due to item unavailability"; } diff --git a/src/main/java/org/folio/dcb/utils/TransactionHelper.java b/src/main/java/org/folio/dcb/utils/TransactionHelper.java index 6468ad25..93888ed4 100644 --- a/src/main/java/org/folio/dcb/utils/TransactionHelper.java +++ b/src/main/java/org/folio/dcb/utils/TransactionHelper.java @@ -57,6 +57,7 @@ public static EventData parseRequestEvent(String eventPayload){ && kafkaEvent.getNewNode().has(STATUS)){ EventData eventData = new EventData(); eventData.setRequestId(kafkaEvent.getNewNode().get("id").asText()); + eventData.setDcbReRequestCancellation(getNodeAsBoolean(kafkaEvent, "dcbReRequestCancellation")); RequestStatus requestStatus = RequestStatus.from(kafkaEvent.getNewNode().get(STATUS).asText()); switch (requestStatus) { case OPEN_IN_TRANSIT -> eventData.setType(EventData.EventType.IN_TRANSIT); @@ -69,6 +70,11 @@ public static EventData parseRequestEvent(String eventPayload){ } return null; } + + private static boolean getNodeAsBoolean(KafkaEvent kafkaEvent, String name) { + return kafkaEvent.getNewNode().get(name).asBoolean(); + } + private static boolean checkDcbRequest(KafkaEvent kafkaEvent) { return (kafkaEvent.getNewNode().has(INSTANCE) && kafkaEvent.getNewNode().get(INSTANCE).has(TITLE) && kafkaEvent.getNewNode().get(INSTANCE).get(TITLE).asText().equals(DCB_INSTANCE_TITLE)) || (kafkaEvent.getNewNode().has(REQUESTER) diff --git a/src/main/resources/swagger.api/schemas/CirculationRequest.yaml b/src/main/resources/swagger.api/schemas/CirculationRequest.yaml index 69a456ea..a26f8555 100644 --- a/src/main/resources/swagger.api/schemas/CirculationRequest.yaml +++ b/src/main/resources/swagger.api/schemas/CirculationRequest.yaml @@ -78,8 +78,8 @@ CirculationRequest: pickupServicePointId: description: The ID of the Service Point where this request can be picked up type: string - isSuppressNotification: - description: Flag to suppress sending cancellation notifications. If true, no notification will be sent when cancelling the request + isDcbReRequestCancellation: + description: Indicates whether the request was cancelled during a DCB transaction update type: boolean item: $ref: CirculationRequest.yaml#/item diff --git a/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java b/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java index e45536dc..ab8b6dd7 100644 --- a/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java +++ b/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java @@ -7,7 +7,6 @@ import org.folio.dcb.repository.TransactionAuditRepository; import org.folio.dcb.repository.TransactionRepository; import org.folio.spring.service.SystemUserScopedExecutionService; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; diff --git a/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java b/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java index 557e045b..e20d9d43 100644 --- a/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java +++ b/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java @@ -37,6 +37,7 @@ class CirculationRequestEventListenerTest extends BaseIT { private static final String CHECK_IN_UNDEFINED_EVENT_SAMPLE = getMockDataAsString("mockdata/kafka/request_undefined.json"); private static final String REQUEST_CANCEL_EVENT_SAMPLE = getMockDataAsString("mockdata/kafka/cancel_request.json"); private static final String REQUEST_CANCEL_EVENT_FOR_DCB_SAMPLE = getMockDataAsString("mockdata/kafka/cancel_request_dcb.json"); + private static final String CANCELLATION_DCB_REREQUEST_SAMPLE = getMockDataAsString("mockdata/kafka/cancellation_dcb_rerequest.json"); @Autowired private CirculationEventListener eventListener ; @@ -53,6 +54,17 @@ void handleNonDcbRequestTest() { eventListener.handleRequestEvent(REQUEST_EVENT_SAMPLE_NON_DCB, messageHeaders); Mockito.verify(transactionRepository, times(0)).save(any()); } + + @Test + void handleCancelRequestEventWhenTransactionDcbUpdates() { + var transactionEntity = createTransactionEntity(); + MessageHeaders messageHeaders = getMessageHeaders(); + when(transactionRepository.findTransactionByRequestIdAndStatusNotInClosed(any())).thenReturn(Optional.of(transactionEntity)); + eventListener.handleRequestEvent(CANCELLATION_DCB_REREQUEST_SAMPLE, messageHeaders); + Mockito.verify(transactionRepository, times(0)).save(any()); + } + + @Test void handleCheckInEventInPickupForDcbFromOpenToAwaitingPickupTest() { var transactionEntity = createTransactionEntity(); diff --git a/src/test/java/org/folio/dcb/service/CirculationServiceTest.java b/src/test/java/org/folio/dcb/service/CirculationServiceTest.java index 77f62ec3..8ec991ae 100644 --- a/src/test/java/org/folio/dcb/service/CirculationServiceTest.java +++ b/src/test/java/org/folio/dcb/service/CirculationServiceTest.java @@ -1,7 +1,18 @@ package org.folio.dcb.service; -import feign.FeignException; +import static org.folio.dcb.utils.EntityUtils.createCirculationRequest; +import static org.folio.dcb.utils.EntityUtils.createTransactionEntity; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.UUID; + import org.folio.dcb.client.feign.CirculationClient; +import org.folio.dcb.domain.dto.CirculationRequest; +import org.folio.dcb.domain.entity.TransactionEntity; import org.folio.dcb.exception.CirculationRequestException; import org.folio.dcb.service.impl.CirculationServiceImpl; import org.junit.jupiter.api.Test; @@ -10,15 +21,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.UUID; - -import static org.folio.dcb.utils.EntityUtils.createCirculationRequest; -import static org.folio.dcb.utils.EntityUtils.createTransactionEntity; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import feign.FeignException; @ExtendWith(MockitoExtension.class) class CirculationServiceTest { @@ -44,6 +47,17 @@ void checkInByBarcodeWithServicePointTest(){ verify(circulationClient).checkInByBarcode(any()); } + @Test + void shouldUpdateRequestApiWithIsDcbRerequestCancellationTrue() { + CirculationRequest fetchedRequest = createCirculationRequest(); + fetchedRequest.setIsDcbReRequestCancellation(null); + CirculationRequest requestToBeCancelled = createCirculationRequest(); + requestToBeCancelled.setIsDcbReRequestCancellation(true); + when(circulationRequestService.getCancellationRequestIfOpenOrNull(anyString())).thenReturn(fetchedRequest); + circulationService.cancelRequest(createTransactionEntity(), true); + verify(circulationClient).updateRequest(requestToBeCancelled.getId(), requestToBeCancelled); + } + @Test void cancelRequestTest() { when(circulationRequestService.getCancellationRequestIfOpenOrNull(anyString())).thenReturn(createCirculationRequest()); @@ -53,9 +67,12 @@ void cancelRequestTest() { @Test void shouldThrowExceptionWhenRequestIsNotUpdated() { + TransactionEntity transactionEntity = createTransactionEntity(); when(circulationRequestService.getCancellationRequestIfOpenOrNull(anyString())).thenReturn(createCirculationRequest()); when(circulationClient.updateRequest(anyString(), any())).thenThrow(FeignException.BadRequest.class); - assertThrows(CirculationRequestException.class, () -> circulationService.cancelRequest(createTransactionEntity(), false)); + assertThrows(CirculationRequestException.class, () -> { + circulationService.cancelRequest(transactionEntity, false); + }); } } diff --git a/src/test/java/org/folio/dcb/utils/EntityUtils.java b/src/test/java/org/folio/dcb/utils/EntityUtils.java index 547e9a1a..e7e1e79c 100644 --- a/src/test/java/org/folio/dcb/utils/EntityUtils.java +++ b/src/test/java/org/folio/dcb/utils/EntityUtils.java @@ -63,7 +63,7 @@ public class EntityUtils { public static String EXISTED_INVENTORY_ITEM_BARCODE = "INVENTORY_ITEM"; public static String PATRON_TYPE_USER_ID = "18c1741d-e678-4c8e-9fe7-cfaeefab5eea"; public static String REQUEST_ID = "398501a2-5c97-4ba6-9ee7-d1cd6433cb98"; - public static String DCB_NEW_BARCODE = "NEW_BARCODE"; + public static final String DCB_NEW_BARCODE = "398501a2-5c97-4ba6-9ee7-d1cd6433cb91"; public static DcbTransaction createDcbTransactionByRole(DcbTransaction.RoleEnum role) { return DcbTransaction.builder() diff --git a/src/test/resources/mappings/circulation-item.json b/src/test/resources/mappings/circulation-item.json index 41c5d445..860e677e 100644 --- a/src/test/resources/mappings/circulation-item.json +++ b/src/test/resources/mappings/circulation-item.json @@ -95,7 +95,7 @@ { "request": { "method": "GET", - "url": "/circulation-item?query=barcode%3D%3D%22NEW_BARCODE%22" + "url": "/circulation-item?query=barcode%3D%3D%22398501a2-5c97-4ba6-9ee7-d1cd6433cb91%22" }, "response": { "status": 200, diff --git a/src/test/resources/mappings/inventory.json b/src/test/resources/mappings/inventory.json index e4eddd25..6573a5c6 100644 --- a/src/test/resources/mappings/inventory.json +++ b/src/test/resources/mappings/inventory.json @@ -224,7 +224,7 @@ { "request": { "method": "GET", - "url": "/item-storage/items?query=barcode%3D%3DNEW_BARCODE" + "url": "/item-storage/items?query=barcode%3D%3D398501a2-5c97-4ba6-9ee7-d1cd6433cb91" }, "response": { "status": 200, diff --git a/src/test/resources/mockdata/kafka/cancel_request.json b/src/test/resources/mockdata/kafka/cancel_request.json index f45127d8..3e9be1ce 100644 --- a/src/test/resources/mockdata/kafka/cancel_request.json +++ b/src/test/resources/mockdata/kafka/cancel_request.json @@ -17,7 +17,8 @@ "cancellationReasonId": "50ed35b2-1397-4e83-a76b-642adf91ca2a", "cancelledByUserId": "7187c6f3-41ec-5731-b551-7f0092abb4c6", "cancellationAdditionalInformation": "test", - "cancelledDate": "2023-11-06T12:18:36.938+00:00" + "cancelledDate": "2023-11-06T12:18:36.938+00:00", + "dcbReRequestCancellation": false } } } diff --git a/src/test/resources/mockdata/kafka/cancel_request_dcb.json b/src/test/resources/mockdata/kafka/cancel_request_dcb.json index 4924e559..0950f43d 100644 --- a/src/test/resources/mockdata/kafka/cancel_request_dcb.json +++ b/src/test/resources/mockdata/kafka/cancel_request_dcb.json @@ -24,7 +24,8 @@ "requester": { "lastName": "DcbSystem", "barcode": "dcbDemo21" - } + }, + "dcbReRequestCancellation": false } } } diff --git a/src/test/resources/mockdata/kafka/cancellation_dcb_rerequest.json b/src/test/resources/mockdata/kafka/cancellation_dcb_rerequest.json new file mode 100644 index 00000000..d16838b2 --- /dev/null +++ b/src/test/resources/mockdata/kafka/cancellation_dcb_rerequest.json @@ -0,0 +1,24 @@ +{ + "id": "4a8123fe-a0aa-47ae-9836-71a6cc3cb119", + "type": "UPDATED", + "tenant": "diku", + "timestamp": 1695390940007, + "data": { + "new": { + "id": "299b5ad1-baa6-44fe-a855-0236f852c943", + "requestLevel": "Item", + "requestType": "Page", + "requestDate": "2023-11-06T12:17:52.573+00:00", + "requesterId": "2205005b-ca51-4a04-87fd-938eefa8f6de", + "instanceId": "9d1b77e4-f02e-4b7f-b296-3f2042ddac54", + "holdingsRecordId": "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9", + "itemId": "5b95877d-86c0-4cb7-a0cd-7660b348ae5a", + "status": "Closed - Cancelled", + "cancellationReasonId": "50ed35b2-1397-4e83-a76b-642adf91ca2a", + "cancelledByUserId": "7187c6f3-41ec-5731-b551-7f0092abb4c6", + "cancellationAdditionalInformation": "test", + "cancelledDate": "2023-11-06T12:18:36.938+00:00", + "dcbReRequestCancellation": true + } + } +} \ No newline at end of file diff --git a/src/test/resources/mockdata/kafka/check_in_dcb.json b/src/test/resources/mockdata/kafka/check_in_dcb.json index 014cb2fd..28446d6f 100644 --- a/src/test/resources/mockdata/kafka/check_in_dcb.json +++ b/src/test/resources/mockdata/kafka/check_in_dcb.json @@ -25,7 +25,8 @@ "requester": { "lastName": "DcbSystem", "barcode": "user2" - } + }, + "dcbReRequestCancellation": false } } } diff --git a/src/test/resources/mockdata/kafka/check_in_transit.json b/src/test/resources/mockdata/kafka/check_in_transit.json index 7f48d141..9af72b41 100644 --- a/src/test/resources/mockdata/kafka/check_in_transit.json +++ b/src/test/resources/mockdata/kafka/check_in_transit.json @@ -13,7 +13,8 @@ "instanceId": "9d1b77e4-f02e-4b7f-b296-3f2042ddac54", "holdingsRecordId": "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9", "itemId": "5d2625ef-81eb-4e61-a8a9-87c94ba3764e", - "status": "Open - In transit" + "status": "Open - In transit", + "dcbReRequestCancellation": false } } } diff --git a/src/test/resources/mockdata/kafka/check_in_transit_dcb.json b/src/test/resources/mockdata/kafka/check_in_transit_dcb.json index 8ea68aba..48377923 100644 --- a/src/test/resources/mockdata/kafka/check_in_transit_dcb.json +++ b/src/test/resources/mockdata/kafka/check_in_transit_dcb.json @@ -24,7 +24,8 @@ "requester": { "lastName": "DcbSystem", "barcode": "systemDemoUser1" - } + }, + "dcbReRequestCancellation": false } } } diff --git a/src/test/resources/mockdata/kafka/request_sample.json b/src/test/resources/mockdata/kafka/request_sample.json index 7c9f3f9f..9002dc06 100644 --- a/src/test/resources/mockdata/kafka/request_sample.json +++ b/src/test/resources/mockdata/kafka/request_sample.json @@ -97,7 +97,8 @@ }, "shelvingOrder": "K1 .M44 v.72:no.6-7,10-12 1986:July-Aug.,Oct.-Dec.", "pickupServicePointName": "Circ Desk 1" - } + }, + "dcbReRequestCancellation": false } } } diff --git a/src/test/resources/mockdata/kafka/request_undefined.json b/src/test/resources/mockdata/kafka/request_undefined.json index 1854bdb2..a46099d9 100644 --- a/src/test/resources/mockdata/kafka/request_undefined.json +++ b/src/test/resources/mockdata/kafka/request_undefined.json @@ -13,7 +13,8 @@ "instanceId": "9d1b77e4-f02e-4b7f-b296-3f2042ddac54", "holdingsRecordId": "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9", "itemId": "5d2625ef-81eb-4e61-a8a9-87c94ba3764e", - "status": "aaa" + "status": "aaa", + "dcbReRequestCancellation": false } } }