From b7d38fddcb464b54a2e918ec209ee93c814ce2e6 Mon Sep 17 00:00:00 2001 From: Vignesh-Kalyanasundaram Date: Thu, 5 Dec 2024 15:11:54 +0530 Subject: [PATCH 1/3] UXPROD-5001 Code refactoring --- .../controller/TransactionApiController.java | 6 +-- .../dcb/domain/mapper/TransactionMapper.java | 10 ++--- .../dcb/service/TransactionsService.java | 4 +- .../dcb/service/impl/BaseLibraryService.java | 6 +-- .../service/impl/TransactionsServiceImpl.java | 6 +-- .../swagger.api/dcb_transaction.yaml | 6 +-- .../schemas/DcbTransactionUpdate.yaml | 20 ---------- .../swagger.api/schemas/dcbUpdateItem.yaml | 18 +++++++++ .../schemas/dcbUpdateTransaction.yaml | 6 +++ .../TransactionApiControllerTest.java | 38 +++++++++++++++++++ .../CirculationRequestEventListenerTest.java | 12 +++++- .../java/org/folio/dcb/utils/EntityUtils.java | 13 +++++++ ...el_request_due_to_item_unavailability.json | 23 +++++++++++ 13 files changed, 128 insertions(+), 40 deletions(-) delete mode 100644 src/main/resources/swagger.api/schemas/DcbTransactionUpdate.yaml create mode 100644 src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml create mode 100644 src/main/resources/swagger.api/schemas/dcbUpdateTransaction.yaml create mode 100644 src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json diff --git a/src/main/java/org/folio/dcb/controller/TransactionApiController.java b/src/main/java/org/folio/dcb/controller/TransactionApiController.java index 6c40b597..dd569b76 100644 --- a/src/main/java/org/folio/dcb/controller/TransactionApiController.java +++ b/src/main/java/org/folio/dcb/controller/TransactionApiController.java @@ -3,7 +3,7 @@ import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; import org.folio.dcb.domain.dto.DcbTransaction; -import org.folio.dcb.domain.dto.DcbTransactionUpdate; +import org.folio.dcb.domain.dto.DcbUpdateTransaction; import org.folio.dcb.domain.dto.TransactionStatus; import org.folio.dcb.domain.dto.TransactionStatusResponseCollection; import org.folio.dcb.rest.resource.TransactionsApi; @@ -76,8 +76,8 @@ public ResponseEntity getTransactionStatusL } @Override - public ResponseEntity updateTransactionDetails(String dcbTransactionId, DcbTransactionUpdate dcbTransactionUpdate) { - transactionsService.updateTransactionDetails(dcbTransactionId, dcbTransactionUpdate); + public ResponseEntity updateTransactionDetails(String dcbTransactionId, DcbUpdateTransaction dcbUpdateTransaction) { + transactionsService.updateTransactionDetails(dcbTransactionId, dcbUpdateTransaction); return ResponseEntity.status(HttpStatus.NO_CONTENT) .build(); } diff --git a/src/main/java/org/folio/dcb/domain/mapper/TransactionMapper.java b/src/main/java/org/folio/dcb/domain/mapper/TransactionMapper.java index ba1762d5..e4e91766 100644 --- a/src/main/java/org/folio/dcb/domain/mapper/TransactionMapper.java +++ b/src/main/java/org/folio/dcb/domain/mapper/TransactionMapper.java @@ -3,7 +3,7 @@ import org.folio.dcb.domain.dto.DcbItem; import org.folio.dcb.domain.dto.DcbPatron; import org.folio.dcb.domain.dto.DcbPickup; -import org.folio.dcb.domain.dto.DcbTransactionUpdateItem; +import org.folio.dcb.domain.dto.DcbUpdateItem; import org.folio.dcb.domain.dto.TransactionStatusResponseList; import org.folio.dcb.domain.entity.TransactionAuditEntity; import org.folio.dcb.domain.entity.TransactionEntity; @@ -92,12 +92,12 @@ public DcbPickup mapTransactionEntityToDcbPickup(TransactionEntity transactionEn .build(); } - public DcbItem convertTransactionUpdateItemToDcbItem(DcbTransactionUpdateItem updatedItem, TransactionEntity entity) { + public DcbItem convertTransactionUpdateItemToDcbItem(DcbUpdateItem dcbUpdateItem, TransactionEntity entity) { return DcbItem .builder() - .lendingLibraryCode(updatedItem.getLendingLibraryCode()) - .barcode(updatedItem.getBarcode()) - .materialType(updatedItem.getMaterialType()) + .lendingLibraryCode(dcbUpdateItem.getLendingLibraryCode()) + .barcode(dcbUpdateItem.getBarcode()) + .materialType(dcbUpdateItem.getMaterialType()) .title(entity.getItemTitle()) .build(); } diff --git a/src/main/java/org/folio/dcb/service/TransactionsService.java b/src/main/java/org/folio/dcb/service/TransactionsService.java index f08b64c9..549db7d7 100644 --- a/src/main/java/org/folio/dcb/service/TransactionsService.java +++ b/src/main/java/org/folio/dcb/service/TransactionsService.java @@ -1,7 +1,7 @@ package org.folio.dcb.service; import org.folio.dcb.domain.dto.DcbTransaction; -import org.folio.dcb.domain.dto.DcbTransactionUpdate; +import org.folio.dcb.domain.dto.DcbUpdateTransaction; import org.folio.dcb.domain.dto.TransactionStatus; import org.folio.dcb.domain.dto.TransactionStatusResponse; import org.folio.dcb.domain.dto.TransactionStatusResponseCollection; @@ -18,6 +18,6 @@ public interface TransactionsService { TransactionStatusResponse updateTransactionStatus(String dcbTransactionId, TransactionStatus transactionStatus); TransactionStatusResponse getTransactionStatusById(String dcbTransactionId); TransactionStatusResponseCollection getTransactionStatusList(OffsetDateTime fromDate, OffsetDateTime toDate, Integer pageNumber, Integer pageSize); - void updateTransactionDetails(String dcbTransactionId, DcbTransactionUpdate dcbTransactionUpdate); + void updateTransactionDetails(String dcbTransactionId, DcbUpdateTransaction dcbUpdateTransaction); } diff --git a/src/main/java/org/folio/dcb/service/impl/BaseLibraryService.java b/src/main/java/org/folio/dcb/service/impl/BaseLibraryService.java index e1f6345c..f0f5ee05 100644 --- a/src/main/java/org/folio/dcb/service/impl/BaseLibraryService.java +++ b/src/main/java/org/folio/dcb/service/impl/BaseLibraryService.java @@ -8,7 +8,7 @@ import org.folio.dcb.domain.dto.DcbItem; import org.folio.dcb.domain.dto.DcbPatron; import org.folio.dcb.domain.dto.DcbTransaction; -import org.folio.dcb.domain.dto.DcbTransactionUpdateItem; +import org.folio.dcb.domain.dto.DcbUpdateItem; import org.folio.dcb.domain.dto.TransactionStatus; import org.folio.dcb.domain.dto.TransactionStatusResponse; import org.folio.dcb.domain.entity.TransactionEntity; @@ -138,9 +138,9 @@ public void updateTransactionEntity(TransactionEntity transactionEntity, Transac transactionRepository.save(transactionEntity); } - public void updateTransactionDetails(TransactionEntity transactionEntity, DcbTransactionUpdateItem updatedItem) { + public void updateTransactionDetails(TransactionEntity transactionEntity, DcbUpdateItem dcbUpdateItem) { DcbPatron dcbPatron = transactionMapper.mapTransactionEntityToDcbPatron(transactionEntity); - DcbItem dcbItem = transactionMapper.convertTransactionUpdateItemToDcbItem(updatedItem, transactionEntity); + DcbItem dcbItem = transactionMapper.convertTransactionUpdateItemToDcbItem(dcbUpdateItem, transactionEntity); checkItemExistsInInventoryAndThrow(dcbItem.getBarcode()); CirculationItem item = circulationItemService.checkIfItemExistsAndCreate(dcbItem, transactionEntity.getServicePointId()); dcbItem.setId(item.getId()); diff --git a/src/main/java/org/folio/dcb/service/impl/TransactionsServiceImpl.java b/src/main/java/org/folio/dcb/service/impl/TransactionsServiceImpl.java index 9283501f..050c3176 100644 --- a/src/main/java/org/folio/dcb/service/impl/TransactionsServiceImpl.java +++ b/src/main/java/org/folio/dcb/service/impl/TransactionsServiceImpl.java @@ -3,7 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.folio.dcb.domain.dto.DcbTransaction; -import org.folio.dcb.domain.dto.DcbTransactionUpdate; +import org.folio.dcb.domain.dto.DcbUpdateTransaction; import org.folio.dcb.domain.dto.TransactionStatus; import org.folio.dcb.domain.dto.TransactionStatusResponse; import org.folio.dcb.domain.dto.TransactionStatusResponseCollection; @@ -112,7 +112,7 @@ public TransactionStatusResponseCollection getTransactionStatusList(OffsetDateTi } @Override - public void updateTransactionDetails(String dcbTransactionId, DcbTransactionUpdate dcbTransactionUpdate) { + public void updateTransactionDetails(String dcbTransactionId, DcbUpdateTransaction dcbUpdateTransaction) { var transactionEntity = getTransactionEntityOrThrow(dcbTransactionId); if (!TransactionStatus.StatusEnum.CREATED.equals(transactionEntity.getStatus())) { throw new StatusException(String.format( @@ -121,7 +121,7 @@ public void updateTransactionDetails(String dcbTransactionId, DcbTransactionUpda if (DcbTransaction.RoleEnum.LENDER.equals(transactionEntity.getRole())) { throw new IllegalArgumentException("Item details cannot be updated for lender role"); } - baseLibraryService.updateTransactionDetails(transactionEntity, dcbTransactionUpdate.getItem()); + baseLibraryService.updateTransactionDetails(transactionEntity, dcbUpdateTransaction.getItem()); } private TransactionStatusResponse generateTransactionStatusResponseFromTransactionEntity(TransactionEntity transactionEntity) { diff --git a/src/main/resources/swagger.api/dcb_transaction.yaml b/src/main/resources/swagger.api/dcb_transaction.yaml index ea49ca94..45f0ed87 100644 --- a/src/main/resources/swagger.api/dcb_transaction.yaml +++ b/src/main/resources/swagger.api/dcb_transaction.yaml @@ -32,7 +32,7 @@ paths: parameters: - $ref: '#/components/parameters/dcbTransactionId' requestBody: - $ref: "#/components/requestBodies/DCBTransactionUpdate" + $ref: "#/components/requestBodies/DcbUpdateTransaction" responses: '204': description: 'Transaction updated successfully' @@ -126,13 +126,13 @@ components: application/json: schema: $ref: "schemas/dcbTransaction.yaml#/DcbTransaction" - DCBTransactionUpdate: + DcbUpdateTransaction: description: DCB transaction update object required: true content: application/json: schema: - $ref: "schemas/DcbTransactionUpdate.yaml#/DcbTransactionUpdate" + $ref: "schemas/DcbUpdateTransaction.yaml#/DcbUpdateTransaction" responses: TransactionStatus: description: Transaction Status object diff --git a/src/main/resources/swagger.api/schemas/DcbTransactionUpdate.yaml b/src/main/resources/swagger.api/schemas/DcbTransactionUpdate.yaml deleted file mode 100644 index a0ae4a40..00000000 --- a/src/main/resources/swagger.api/schemas/DcbTransactionUpdate.yaml +++ /dev/null @@ -1,20 +0,0 @@ -DcbTransactionUpdate: - type: object - properties: - item: - properties: - barcode: - description: The barcode of the item as specified in the lending library - type: string - materialType: - description: The “hub-normalized” form of the item item type, used in the circulation rules for determining the correct loan policy. - type: string - lendingLibraryCode: - description: The code which identifies the lending library - type: string - additionalProperties: false - required: - - barcode - - materialType - - lendingLibraryCode - diff --git a/src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml b/src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml new file mode 100644 index 00000000..92264987 --- /dev/null +++ b/src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml @@ -0,0 +1,18 @@ +DcbUpdateItem: + description: Item metadata required for updating the existing transaction + type: object + properties: + barcode: + description: The barcode of the item as specified in the lending library + type: string + materialType: + description: The “hub-normalized” form of the item item type, used in the circulation rules for determining the correct loan policy. + type: string + lendingLibraryCode: + description: The code which identifies the lending library + type: string + additionalProperties: false + required: + - barcode + - materialType + - lendingLibraryCode diff --git a/src/main/resources/swagger.api/schemas/dcbUpdateTransaction.yaml b/src/main/resources/swagger.api/schemas/dcbUpdateTransaction.yaml new file mode 100644 index 00000000..c08ed5c1 --- /dev/null +++ b/src/main/resources/swagger.api/schemas/dcbUpdateTransaction.yaml @@ -0,0 +1,6 @@ +DcbUpdateTransaction: + type: object + properties: + item: + $ref: 'dcbUpdateItem.yaml#/DcbUpdateItem' + diff --git a/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java b/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java index 5edbc7ff..540b1cc5 100644 --- a/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java +++ b/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java @@ -983,9 +983,47 @@ void getTransactionStatusUpdateListTest() throws Exception { .andExpect(jsonPath("$.maximumPageNumber", is(2))) .andExpect(jsonPath("$.transactions[*].status", containsInRelativeOrder("ITEM_CHECKED_OUT", "ITEM_CHECKED_IN"))); + } + + @Test + void createAndUpdateBorrowerTransactionTest() throws Exception { + removeExistedTransactionFromDbIfSoExists(); + removeExistingTransactionsByItemId(ITEM_ID); + this.mockMvc.perform( + post("/transactions/" + DCB_TRANSACTION_ID) + .content(asJsonString(createDcbTransactionByRole(BORROWER))) + .headers(defaultHeaders()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.status").value("CREATED")) + .andExpect(jsonPath("$.item").value(createDcbItem())) + .andExpect(jsonPath("$.patron").value(createDcbPatronWithExactPatronId(EXISTED_PATRON_ID))); + + //Trying to create another transaction with same transaction id + this.mockMvc.perform( + post("/transactions/" + DCB_TRANSACTION_ID) + .content(asJsonString(createDcbTransactionByRole(BORROWER))) + .headers(defaultHeaders()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpectAll(status().is4xxClientError(), + jsonPath("$.errors[0].code", is("DUPLICATE_ERROR"))); + + // check for DUPLICATE_ERROR propagated into transactions_audit. + systemUserScopedExecutionService.executeAsyncSystemUserScoped( + TENANT, + () -> { + TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(DCB_TRANSACTION_ID) + .orElse(null); + Assertions.assertNotNull(auditExisting); + Assertions.assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); + Assertions.assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } + ); } + private void removeExistedTransactionFromDbIfSoExists() { systemUserScopedExecutionService.executeAsyncSystemUserScoped(TENANT, () -> { if (transactionRepository.existsById(DCB_TRANSACTION_ID)){ diff --git a/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java b/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java index ba2ac32f..b96fe678 100644 --- a/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java +++ b/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java @@ -36,8 +36,8 @@ class CirculationRequestEventListenerTest extends BaseIT { private static final String CHECK_IN_TRANSIT_EVENT_FOR_DCB_SAMPLE = getMockDataAsString("mockdata/kafka/check_in_transit_dcb.json"); 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 REQUEST_CANCEL_FOR_ITEM_UNAVAILABILITY_SAMPLE = getMockDataAsString("mockdata/kafka/cancel_request_due_to_item_unavailability.json"); @Autowired private CirculationEventListener eventListener ; @@ -104,6 +104,16 @@ void handleCancelRequestForDcbTest() { Mockito.verify(transactionRepository).save(any()); } + @Test + void handleCancelRequestDueToItemUnavailabilityTest() { + var transactionEntity = createTransactionEntity(); + transactionEntity.setRole(BORROWING_PICKUP); + MessageHeaders messageHeaders = getMessageHeaders(); + when(transactionRepository.findTransactionByRequestIdAndStatusNotInClosed(any())).thenReturn(Optional.of(transactionEntity)); + eventListener.handleRequestEvent(REQUEST_CANCEL_FOR_ITEM_UNAVAILABILITY_SAMPLE, messageHeaders); + Mockito.verify(transactionRepository, never()).save(any()); + } + @Test void handleOpenRequestTest() { diff --git a/src/test/java/org/folio/dcb/utils/EntityUtils.java b/src/test/java/org/folio/dcb/utils/EntityUtils.java index 48d1b1e1..ecb0eda2 100644 --- a/src/test/java/org/folio/dcb/utils/EntityUtils.java +++ b/src/test/java/org/folio/dcb/utils/EntityUtils.java @@ -11,6 +11,8 @@ import org.folio.dcb.domain.dto.DcbItem; import org.folio.dcb.domain.dto.DcbPatron; import org.folio.dcb.domain.dto.DcbPickup; +import org.folio.dcb.domain.dto.DcbUpdateTransaction; +import org.folio.dcb.domain.dto.DcbUpdateItem; import org.folio.dcb.domain.dto.TransactionStatusResponse; import org.folio.dcb.domain.dto.User; import org.folio.dcb.domain.dto.TransactionStatus; @@ -61,6 +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 DcbTransaction createDcbTransactionByRole(DcbTransaction.RoleEnum role) { return DcbTransaction.builder() @@ -118,6 +121,16 @@ public static DcbItem createDcbItem() { .build(); } + public static DcbUpdateTransaction createDcbTransactionUpdate() { + return DcbUpdateTransaction + .builder() + .item(DcbUpdateItem + .builder() + .barcode("") + .build()) + .build(); + } + public static CirculationRequest createCirculationRequest() { return CirculationRequest.builder() .id(CIRCULATION_REQUEST_ID) diff --git a/src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json b/src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json new file mode 100644 index 00000000..9e030a6f --- /dev/null +++ b/src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json @@ -0,0 +1,23 @@ +{ + "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": "Request cancelled due to item unavailability", + "cancelledDate": "2023-11-06T12:18:36.938+00:00" + } + } +} From f9c001821a89de179bf221fcf851ca8fd142ef93 Mon Sep 17 00:00:00 2001 From: Vignesh-Kalyanasundaram Date: Fri, 6 Dec 2024 01:28:55 +0530 Subject: [PATCH 2/3] UXPROD-5001 Code refactoring and adding test case --- .../kafka/CirculationEventListener.java | 4 +- .../folio/dcb/listener/kafka/EventData.java | 1 - .../folio/dcb/service/CirculationService.java | 3 +- .../service/impl/CirculationServiceImpl.java | 3 - .../folio/dcb/utils/TransactionHelper.java | 3 - .../swagger.api/dcb_transaction.yaml | 2 +- .../TransactionApiControllerTest.java | 81 ++++++++++++------- .../CirculationRequestEventListenerTest.java | 12 --- .../java/org/folio/dcb/utils/EntityUtils.java | 4 +- .../resources/mappings/circulation-item.json | 16 +++- src/test/resources/mappings/circulation.json | 5 +- src/test/resources/mappings/inventory.json | 13 +++ .../resources/mappings/material-types.json | 13 +++ ...el_request_due_to_item_unavailability.json | 23 ------ 14 files changed, 101 insertions(+), 82 deletions(-) delete mode 100644 src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json 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 839f0dc6..85e80095 100644 --- a/src/main/java/org/folio/dcb/listener/kafka/CirculationEventListener.java +++ b/src/main/java/org/folio/dcb/listener/kafka/CirculationEventListener.java @@ -17,7 +17,6 @@ import static org.folio.dcb.domain.dto.DcbTransaction.RoleEnum.BORROWING_PICKUP; import static org.folio.dcb.domain.dto.DcbTransaction.RoleEnum.LENDER; import static org.folio.dcb.domain.dto.DcbTransaction.RoleEnum.PICKUP; -import static org.folio.dcb.utils.DCBConstants.ITEM_UNAVAILABLE_CANCELLATION_MSG; import static org.folio.dcb.utils.TransactionHelper.getHeaderValue; import static org.folio.dcb.utils.TransactionHelper.parseLoanEvent; import static org.folio.dcb.utils.TransactionHelper.parseRequestEvent; @@ -79,8 +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 && - !ITEM_UNAVAILABLE_CANCELLATION_MSG.equals(eventData.getCancellationAdditionalInformation())) { + if (eventData.getType() == EventData.EventType.CANCEL) { 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 579f16e0..0b786a2b 100644 --- a/src/main/java/org/folio/dcb/listener/kafka/EventData.java +++ b/src/main/java/org/folio/dcb/listener/kafka/EventData.java @@ -8,7 +8,6 @@ public class EventData { private String itemId; private String requestId; private boolean isDcb; - private String cancellationAdditionalInformation; public enum EventType { CHECK_IN, CHECK_OUT, IN_TRANSIT, AWAITING_PICKUP, CANCEL diff --git a/src/main/java/org/folio/dcb/service/CirculationService.java b/src/main/java/org/folio/dcb/service/CirculationService.java index e8641865..651955bb 100644 --- a/src/main/java/org/folio/dcb/service/CirculationService.java +++ b/src/main/java/org/folio/dcb/service/CirculationService.java @@ -20,8 +20,7 @@ public interface CirculationService { /** * Cancels a transaction request based on the provided transaction details. *

- * If {@code isItemUnavailableCancellation} is {@code true}, the cancellation reason - * will be updated to indicate item unavailability, and the notification for this + * If {@code isItemUnavailableCancellation} is {@code true}, the notification for this * cancellation will be suppressed by setting the {@code suppressNotification} flag * to {@code true}. *

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 bf6496af..b4110b26 100644 --- a/src/main/java/org/folio/dcb/service/impl/CirculationServiceImpl.java +++ b/src/main/java/org/folio/dcb/service/impl/CirculationServiceImpl.java @@ -14,8 +14,6 @@ import org.springframework.stereotype.Service; import java.time.OffsetDateTime; -import static org.folio.dcb.utils.DCBConstants.ITEM_UNAVAILABLE_CANCELLATION_MSG; - @Service @Log4j2 @RequiredArgsConstructor @@ -49,7 +47,6 @@ public void cancelRequest(TransactionEntity dcbTransaction, boolean isItemUnavai if (request != null){ try { if (isItemUnavailableCancellation) { - request.setCancellationAdditionalInformation(ITEM_UNAVAILABLE_CANCELLATION_MSG); request.setIsSuppressNotification(true); } circulationClient.updateRequest(request.getId(), request); diff --git a/src/main/java/org/folio/dcb/utils/TransactionHelper.java b/src/main/java/org/folio/dcb/utils/TransactionHelper.java index 5613bcc4..6468ad25 100644 --- a/src/main/java/org/folio/dcb/utils/TransactionHelper.java +++ b/src/main/java/org/folio/dcb/utils/TransactionHelper.java @@ -22,7 +22,6 @@ public class TransactionHelper { public static final String LASTNAME = "lastName"; public static final String DCB_INSTANCE_TITLE = "DCB_INSTANCE"; public static final String DCB_REQUESTER_LASTNAME = "DcbSystem"; - public static final String CANCELLATION_ADDITIONAL_INFORMATION = "cancellationAdditionalInformation"; private TransactionHelper(){} @@ -66,8 +65,6 @@ public static EventData parseRequestEvent(String eventPayload){ default -> log.info("parseRequestEvent:: Request status {} is not supported", requestStatus); } eventData.setDcb(checkDcbRequest(kafkaEvent)); - eventData.setCancellationAdditionalInformation(kafkaEvent.getNewNode().has(CANCELLATION_ADDITIONAL_INFORMATION) ? - kafkaEvent.getNewNode().get(CANCELLATION_ADDITIONAL_INFORMATION).asText() : null); return eventData; } return null; diff --git a/src/main/resources/swagger.api/dcb_transaction.yaml b/src/main/resources/swagger.api/dcb_transaction.yaml index 45f0ed87..a64bc437 100644 --- a/src/main/resources/swagger.api/dcb_transaction.yaml +++ b/src/main/resources/swagger.api/dcb_transaction.yaml @@ -132,7 +132,7 @@ components: content: application/json: schema: - $ref: "schemas/DcbUpdateTransaction.yaml#/DcbUpdateTransaction" + $ref: "schemas/dcbUpdateTransaction.yaml#/DcbUpdateTransaction" responses: TransactionStatus: description: Transaction Status object diff --git a/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java b/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java index 540b1cc5..e45536dc 100644 --- a/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java +++ b/src/test/java/org/folio/dcb/controller/TransactionApiControllerTest.java @@ -1,5 +1,6 @@ package org.folio.dcb.controller; +import com.jayway.jsonpath.JsonPath; import org.folio.dcb.domain.dto.DcbItem; import org.folio.dcb.domain.dto.TransactionStatus; import org.folio.dcb.domain.entity.TransactionAuditEntity; @@ -10,6 +11,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; import java.time.OffsetDateTime; import java.time.ZoneOffset; @@ -19,6 +21,7 @@ import static org.folio.dcb.domain.dto.DcbTransaction.RoleEnum.BORROWING_PICKUP; import static org.folio.dcb.domain.dto.DcbTransaction.RoleEnum.LENDER; import static org.folio.dcb.domain.dto.DcbTransaction.RoleEnum.PICKUP; +import static org.folio.dcb.utils.EntityUtils.DCB_NEW_BARCODE; import static org.folio.dcb.utils.EntityUtils.DCB_TRANSACTION_ID; import static org.folio.dcb.utils.EntityUtils.DCB_TYPE_USER_ID; import static org.folio.dcb.utils.EntityUtils.EXISTED_INVENTORY_ITEM_BARCODE; @@ -28,6 +31,7 @@ import static org.folio.dcb.utils.EntityUtils.PATRON_TYPE_USER_ID; import static org.folio.dcb.utils.EntityUtils.createDcbItem; import static org.folio.dcb.utils.EntityUtils.createDcbPatronWithExactPatronId; +import static org.folio.dcb.utils.EntityUtils.createDcbTransactionUpdate; import static org.folio.dcb.utils.EntityUtils.createDefaultDcbPatron; import static org.folio.dcb.utils.EntityUtils.createDcbTransactionByRole; import static org.folio.dcb.utils.EntityUtils.createTransactionEntity; @@ -35,6 +39,9 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInRelativeOrder; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; @@ -87,9 +94,9 @@ void createLendingCirculationRequestTest() throws Exception { () -> { TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(DCB_TRANSACTION_ID) .orElse(null); - Assertions.assertNotNull(auditExisting); - Assertions.assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); - Assertions.assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } + assertNotNull(auditExisting); + assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); + assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } ); } @@ -162,9 +169,9 @@ void createBorrowingPickupCirculationRequestTest() throws Exception { () -> { TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(DCB_TRANSACTION_ID) .orElse(null); - Assertions.assertNotNull(auditExisting); - Assertions.assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); - Assertions.assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } + assertNotNull(auditExisting); + assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); + assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } ); } @@ -190,8 +197,8 @@ void createLendingCirculationRequestWithInvalidItemId() throws Exception { () -> { TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(trnId) .orElse(null); - Assertions.assertNotNull(auditExisting); - Assertions.assertEquals(TRANSACTION_AUDIT_ERROR_ACTION, auditExisting.getAction()); } + assertNotNull(auditExisting); + assertEquals(TRANSACTION_AUDIT_ERROR_ACTION, auditExisting.getAction()); } ); } @@ -216,8 +223,8 @@ void createBorrowingPickupCirculationRequestWithInvalidDefaultNotExistedPatronId () -> { TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(trnId) .orElse(null); - Assertions.assertNotNull(auditExisting); - Assertions.assertEquals(TRANSACTION_AUDIT_ERROR_ACTION, auditExisting.getAction()); } + assertNotNull(auditExisting); + assertEquals(TRANSACTION_AUDIT_ERROR_ACTION, auditExisting.getAction()); } ); } @@ -455,9 +462,9 @@ void createTransactionForPickupLibrary() throws Exception { () -> { TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(DCB_TRANSACTION_ID) .orElse(null); - Assertions.assertNotNull(auditExisting); - Assertions.assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); - Assertions.assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } + assertNotNull(auditExisting); + assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); + assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } ); } @@ -513,9 +520,9 @@ void createBorrowerCirculationRequestTest() throws Exception { () -> { TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(DCB_TRANSACTION_ID) .orElse(null); - Assertions.assertNotNull(auditExisting); - Assertions.assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); - Assertions.assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } + assertNotNull(auditExisting); + assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); + assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } ); } @@ -537,7 +544,10 @@ void createBorrowerCirculationRequestWithoutExistingItemTest() throws Exception .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$.status").value("CREATED")) - .andExpect(jsonPath("$.item").value(dcbItem)) + .andExpect(jsonPath("$.item.barcode").value(dcbItem.getBarcode())) + .andExpect(jsonPath("$.item.materialType").value(dcbItem.getMaterialType())) + .andExpect(jsonPath("$.item.lendingLibraryCode").value(dcbItem.getLendingLibraryCode())) + .andExpect(jsonPath("$.item.title").value(dcbItem.getTitle())) .andExpect(jsonPath("$.patron").value(createDcbPatronWithExactPatronId(EXISTED_PATRON_ID))); //Trying to create another transaction with same transaction id @@ -990,7 +1000,7 @@ void createAndUpdateBorrowerTransactionTest() throws Exception { removeExistedTransactionFromDbIfSoExists(); removeExistingTransactionsByItemId(ITEM_ID); - this.mockMvc.perform( + MvcResult result = this.mockMvc.perform( post("/transactions/" + DCB_TRANSACTION_ID) .content(asJsonString(createDcbTransactionByRole(BORROWER))) .headers(defaultHeaders()) @@ -999,28 +1009,39 @@ void createAndUpdateBorrowerTransactionTest() throws Exception { .andExpect(status().isCreated()) .andExpect(jsonPath("$.status").value("CREATED")) .andExpect(jsonPath("$.item").value(createDcbItem())) - .andExpect(jsonPath("$.patron").value(createDcbPatronWithExactPatronId(EXISTED_PATRON_ID))); + .andExpect(jsonPath("$.patron").value(createDcbPatronWithExactPatronId(EXISTED_PATRON_ID))) + .andReturn(); // Capture the response for assertion - //Trying to create another transaction with same transaction id + String responseContent = result.getResponse().getContentAsString(); + String itemId = JsonPath.parse(responseContent).read("$.item.id", String.class); + String itemBarcode = JsonPath.parse(responseContent).read("$.item.barcode", String.class); + String lendingLibraryCode = JsonPath.parse(responseContent).read("$.item.lendingLibraryCode", String.class); + String materialType = JsonPath.parse(responseContent).read("$.item.materialType", String.class); + + //Trying to update the transaction with same transaction id this.mockMvc.perform( - post("/transactions/" + DCB_TRANSACTION_ID) - .content(asJsonString(createDcbTransactionByRole(BORROWER))) + put("/transactions/" + DCB_TRANSACTION_ID) + .content(asJsonString(createDcbTransactionUpdate())) .headers(defaultHeaders()) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) - .andExpectAll(status().is4xxClientError(), - jsonPath("$.errors[0].code", is("DUPLICATE_ERROR"))); + .andExpectAll(status().isNoContent()); - // check for DUPLICATE_ERROR propagated into transactions_audit. + // check whether item related data is updated systemUserScopedExecutionService.executeAsyncSystemUserScoped( TENANT, () -> { - TransactionAuditEntity auditExisting = transactionAuditRepository.findLatestTransactionAuditEntityByDcbTransactionId(DCB_TRANSACTION_ID) + var transactionEntity = transactionRepository.findById(DCB_TRANSACTION_ID) .orElse(null); - Assertions.assertNotNull(auditExisting); - Assertions.assertNotEquals(TRANSACTION_AUDIT_DUPLICATE_ERROR_ACTION, auditExisting.getAction()); - Assertions.assertNotEquals(DUPLICATE_ERROR_TRANSACTION_ID, auditExisting.getTransactionId()); } - ); + assertNotNull(transactionEntity); + assertNotEquals(itemId, transactionEntity.getItemId()); + assertNotEquals(itemBarcode, transactionEntity.getItemBarcode()); + assertEquals(DCB_NEW_BARCODE, transactionEntity.getItemBarcode()); + assertNotEquals(lendingLibraryCode, transactionEntity.getLendingLibraryCode()); + assertEquals("LEN", transactionEntity.getLendingLibraryCode()); + assertNotEquals(materialType, transactionEntity.getMaterialType()); + assertEquals("DVD", transactionEntity.getMaterialType()); + }); } diff --git a/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java b/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java index b96fe678..557e045b 100644 --- a/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java +++ b/src/test/java/org/folio/dcb/listener/CirculationRequestEventListenerTest.java @@ -37,7 +37,6 @@ 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 REQUEST_CANCEL_FOR_ITEM_UNAVAILABILITY_SAMPLE = getMockDataAsString("mockdata/kafka/cancel_request_due_to_item_unavailability.json"); @Autowired private CirculationEventListener eventListener ; @@ -104,17 +103,6 @@ void handleCancelRequestForDcbTest() { Mockito.verify(transactionRepository).save(any()); } - @Test - void handleCancelRequestDueToItemUnavailabilityTest() { - var transactionEntity = createTransactionEntity(); - transactionEntity.setRole(BORROWING_PICKUP); - MessageHeaders messageHeaders = getMessageHeaders(); - when(transactionRepository.findTransactionByRequestIdAndStatusNotInClosed(any())).thenReturn(Optional.of(transactionEntity)); - eventListener.handleRequestEvent(REQUEST_CANCEL_FOR_ITEM_UNAVAILABILITY_SAMPLE, messageHeaders); - Mockito.verify(transactionRepository, never()).save(any()); - } - - @Test void handleOpenRequestTest() { var transactionEntity = createTransactionEntity(); diff --git a/src/test/java/org/folio/dcb/utils/EntityUtils.java b/src/test/java/org/folio/dcb/utils/EntityUtils.java index ecb0eda2..b4e728d7 100644 --- a/src/test/java/org/folio/dcb/utils/EntityUtils.java +++ b/src/test/java/org/folio/dcb/utils/EntityUtils.java @@ -126,7 +126,9 @@ public static DcbUpdateTransaction createDcbTransactionUpdate() { .builder() .item(DcbUpdateItem .builder() - .barcode("") + .barcode(DCB_NEW_BARCODE) + .lendingLibraryCode("LEN") + .materialType("DVD") .build()) .build(); } diff --git a/src/test/resources/mappings/circulation-item.json b/src/test/resources/mappings/circulation-item.json index ba13ee85..41c5d445 100644 --- a/src/test/resources/mappings/circulation-item.json +++ b/src/test/resources/mappings/circulation-item.json @@ -7,7 +7,8 @@ }, "response": { "status": 201, - "body": "{\"id\": \"5b95877d-86c0-4cb7-a0cd-7660b348ae5a\", \"holdingsRecordId\": \"10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9\", \"status\": {\"name\":\"In transit\"}, \"materialTypeId\": \"1a54b431-2e4f-452d-9cae-9cee66c9a892\", \"permanentLoanTypeId\": \"2b94c631-fca9-4892-a730-03ee529ffe27\", \"instanceTitle\": \"ITEM\", \"itemBarcode\": \"DCB_ITEM\", \"pickupLocation\": \"3a40852d-49fd-4df2-a1f9-6e2641a6e91f\"}", + "body": "{{jsonPath request.body '$'}}", + "transformers": ["response-template"], "headers": { "Content-Type": "application/json" } @@ -90,6 +91,19 @@ "Content-Type": "application/json" } } + }, + { + "request": { + "method": "GET", + "url": "/circulation-item?query=barcode%3D%3D%22NEW_BARCODE%22" + }, + "response": { + "status": 200, + "body": "{\n \"totalRecords\": 0,\n \"items\": []\n}", + "headers": { + "Content-Type": "application/json" + } + } } ] } diff --git a/src/test/resources/mappings/circulation.json b/src/test/resources/mappings/circulation.json index 00ec8fc2..72e25d33 100644 --- a/src/test/resources/mappings/circulation.json +++ b/src/test/resources/mappings/circulation.json @@ -6,8 +6,9 @@ "url": "/circulation/requests" }, "response": { - "status": 200, - "body": "{\"id\": \"571b0a2c-8883-40b5-a449-d41fe6017083\"}", + "status": 201, + "body": "{{jsonPath request.body '$'}}", + "transformers": ["response-template"], "headers": { "Content-Type": "application/json" } diff --git a/src/test/resources/mappings/inventory.json b/src/test/resources/mappings/inventory.json index 512502ee..e4eddd25 100644 --- a/src/test/resources/mappings/inventory.json +++ b/src/test/resources/mappings/inventory.json @@ -220,6 +220,19 @@ "Content-Type": "application/json" } } + }, + { + "request": { + "method": "GET", + "url": "/item-storage/items?query=barcode%3D%3DNEW_BARCODE" + }, + "response": { + "status": 200, + "body": "{\n\"items\": [],\n\"totalRecords\": 0,\n \"resultInfo\": {\n \"totalRecords\": 0,\n \"facets\": [],\n \"diagnostics\": []\n }\n}", + "headers": { + "Content-Type": "application/json" + } + } } ] } diff --git a/src/test/resources/mappings/material-types.json b/src/test/resources/mappings/material-types.json index 366e39c5..51d43f7e 100644 --- a/src/test/resources/mappings/material-types.json +++ b/src/test/resources/mappings/material-types.json @@ -12,6 +12,19 @@ "Content-Type": "application/json" } } + }, + { + "request": { + "method": "GET", + "url": "/material-types?query=name%3D%3D%22DVD%22" + }, + "response": { + "status": 200, + "body": "{\"mtypes\": [{\"name\": \"DVD\",\n \"id\": \"1b54b431-2e4f-452d-9cae-9cee66c9a892\",\n \"source\": \"folio\"}]}", + "headers": { + "Content-Type": "application/json" + } + } } ] } diff --git a/src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json b/src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json deleted file mode 100644 index 9e030a6f..00000000 --- a/src/test/resources/mockdata/kafka/cancel_request_due_to_item_unavailability.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "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": "Request cancelled due to item unavailability", - "cancelledDate": "2023-11-06T12:18:36.938+00:00" - } - } -} From 2c13aab160034c5a22c91c865d2fa7d6b9d8c5c3 Mon Sep 17 00:00:00 2001 From: Vignesh-Kalyanasundaram Date: Fri, 6 Dec 2024 01:34:22 +0530 Subject: [PATCH 3/3] UXPROD-5001 Code refactoring --- .../resources/swagger.api/schemas/dcbUpdateItem.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml b/src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml index 92264987..8c6914b1 100644 --- a/src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml +++ b/src/main/resources/swagger.api/schemas/dcbUpdateItem.yaml @@ -11,8 +11,8 @@ DcbUpdateItem: lendingLibraryCode: description: The code which identifies the lending library type: string - additionalProperties: false - required: - - barcode - - materialType - - lendingLibraryCode + additionalProperties: false + required: + - barcode + - materialType + - lendingLibraryCode