From 307ef4c756766e9e7499da4857b6a6c13ae14c8f Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Mon, 7 Oct 2024 14:10:56 +0300 Subject: [PATCH 01/30] MODTLR-77 Pickup transaction attempt --- .../org/folio/domain/entity/EcsTlrEntity.java | 4 + .../org/folio/service/ConsortiaService.java | 4 + .../java/org/folio/service/DcbService.java | 3 +- .../org/folio/service/RequestService.java | 14 +-- .../java/org/folio/service/TenantService.java | 4 +- .../org/folio/service/UserTenantsService.java | 2 + .../service/impl/ConsortiaServiceImpl.java | 33 ++++++ .../folio/service/impl/DcbServiceImpl.java | 22 +++- .../folio/service/impl/EcsTlrServiceImpl.java | 101 +++++++++++++----- .../service/impl/RequestEventHandler.java | 3 +- .../service/impl/RequestServiceImpl.java | 90 +++++++++------- .../folio/service/impl/TenantServiceImpl.java | 20 ++-- .../service/impl/UserTenantsServiceImpl.java | 5 + .../db/changelog/changelog-master.xml | 1 + ...4-10-03-add-intermediate-phase-columns.xml | 19 ++++ .../resources/swagger.api/schemas/EcsTlr.yaml | 9 ++ .../org/folio/service/EcsTlrServiceTest.java | 10 +- .../org/folio/service/RequestServiceTest.java | 98 ++++++++--------- .../org/folio/service/TenantServiceTest.java | 2 +- 19 files changed, 299 insertions(+), 145 deletions(-) create mode 100644 src/main/resources/db/changelog/changes/2024-10-03-add-intermediate-phase-columns.xml diff --git a/src/main/java/org/folio/domain/entity/EcsTlrEntity.java b/src/main/java/org/folio/domain/entity/EcsTlrEntity.java index 3afd5616..28f41f39 100644 --- a/src/main/java/org/folio/domain/entity/EcsTlrEntity.java +++ b/src/main/java/org/folio/domain/entity/EcsTlrEntity.java @@ -40,4 +40,8 @@ public class EcsTlrEntity { private UUID secondaryRequestId; private String secondaryRequestTenantId; private UUID secondaryRequestDcbTransactionId; + private UUID intermediateRequestId; + private String intermediateRequestTenantId; + private UUID intermediateRequestDcbTransactionId; + } diff --git a/src/main/java/org/folio/service/ConsortiaService.java b/src/main/java/org/folio/service/ConsortiaService.java index b1996ec8..12293987 100644 --- a/src/main/java/org/folio/service/ConsortiaService.java +++ b/src/main/java/org/folio/service/ConsortiaService.java @@ -4,4 +4,8 @@ public interface ConsortiaService { TenantCollection getAllDataTenants(String consortiumId); + +// boolean isCurrentTenantCentral(); + +// T executeInTenant(String tenantId, Callable action); } diff --git a/src/main/java/org/folio/service/DcbService.java b/src/main/java/org/folio/service/DcbService.java index c687bfcd..6aa0a001 100644 --- a/src/main/java/org/folio/service/DcbService.java +++ b/src/main/java/org/folio/service/DcbService.java @@ -9,7 +9,8 @@ public interface DcbService { void createLendingTransaction(EcsTlrEntity ecsTlr); - void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request); + void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId); + void createPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId); TransactionStatusResponse getTransactionStatus(UUID transactionId, String tenantId); TransactionStatusResponse updateTransactionStatus(UUID transactionId, TransactionStatus.StatusEnum newStatus, String tenantId); diff --git a/src/main/java/org/folio/service/RequestService.java b/src/main/java/org/folio/service/RequestService.java index 03ce42c6..ddb23506 100644 --- a/src/main/java/org/folio/service/RequestService.java +++ b/src/main/java/org/folio/service/RequestService.java @@ -9,16 +9,18 @@ import org.folio.domain.dto.InventoryItem; import org.folio.domain.dto.ReorderQueue; import org.folio.domain.dto.Request; -import org.folio.domain.entity.EcsTlrEntity; public interface RequestService { - RequestWrapper createPrimaryRequest(Request request, String borrowingTenantId); + RequestWrapper createPrimaryRequest(Request request, String primaryRequestTenantId); - RequestWrapper createSecondaryRequest(Request request, String borrowingTenantId, - Collection lendingTenantIds); + RequestWrapper createSecondaryRequest(Request request, String primaryRequestTenantId, + Collection secondaryRequestTenantIds); - CirculationItem createCirculationItem(EcsTlrEntity ecsTlr, Request secondaryRequest, - String borrowingTenantId, String lendingTenantId); +// CirculationItem createCirculationItem(String itemId, String instanceId, +// String circulationItemTenantId, String inventoryTenantId); + + CirculationItem createCirculationItem(String itemId, String instanceId, + String pickupLocation, String circulationItemTenantId, String inventoryTenantId); CirculationItem updateCirculationItemOnRequestCreation(CirculationItem circulationItem, Request secondaryRequest); diff --git a/src/main/java/org/folio/service/TenantService.java b/src/main/java/org/folio/service/TenantService.java index 99138909..7568ae83 100644 --- a/src/main/java/org/folio/service/TenantService.java +++ b/src/main/java/org/folio/service/TenantService.java @@ -6,7 +6,7 @@ import org.folio.domain.entity.EcsTlrEntity; public interface TenantService { - Optional getBorrowingTenant(EcsTlrEntity ecsTlr); + Optional getPrimaryRequestTenantId(EcsTlrEntity ecsTlr); - List getLendingTenants(EcsTlrEntity ecsTlr); + List getSecondaryRequestTenants(EcsTlrEntity ecsTlr); } diff --git a/src/main/java/org/folio/service/UserTenantsService.java b/src/main/java/org/folio/service/UserTenantsService.java index bf6937a7..bdfaaecc 100644 --- a/src/main/java/org/folio/service/UserTenantsService.java +++ b/src/main/java/org/folio/service/UserTenantsService.java @@ -4,4 +4,6 @@ public interface UserTenantsService { UserTenant findFirstUserTenant(); + + String getCentralTenantId(); } diff --git a/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java b/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java index b56af352..cd7085bf 100644 --- a/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java +++ b/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java @@ -3,6 +3,8 @@ import org.folio.client.feign.ConsortiaClient; import org.folio.domain.dto.TenantCollection; import org.folio.service.ConsortiaService; +import org.folio.service.UserTenantsService; +import org.folio.spring.service.SystemUserScopedExecutionService; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -13,9 +15,40 @@ @RequiredArgsConstructor public class ConsortiaServiceImpl implements ConsortiaService { private final ConsortiaClient consortiaClient; + private final UserTenantsService userTenantsService; + private final SystemUserScopedExecutionService systemUserScopedExecutionService; @Override public TenantCollection getAllDataTenants(String consortiumId) { return consortiaClient.getConsortiaTenants(consortiumId); } + +// @Override +// public boolean isCurrentTenantCentral() { +// var userTenant = userTenantsService.findFirstUserTenant(); +// var centralTenantId = userTenant.getCentralTenantId(); +// var currentTenantId = userTenant.getTenantId(); +// +// if (centralTenantId == null || currentTenantId == null) { +// log.warn("isCurrentTenantCentral:: Cannot determine central tenant or current tenant"); +// return false; +// } +// +// return centralTenantId.equals(currentTenantId); +// } +// +// @Override +// public T executeInTenant(String tenantId, Callable action) { +// if (isCurrentTenantCentral()) { +// try { +// return action.call(); +// } catch (Exception e) { +// log.info("executeInTenant:: Failed to execute in Central tenant"); +// return null; +// } +// } else { +// return systemUserScopedExecutionService.executeSystemUserScoped( +// tenantId, action); +// } +// } } diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java index 01f425d4..3691830c 100644 --- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java +++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java @@ -2,6 +2,7 @@ import static org.folio.domain.dto.DcbTransaction.RoleEnum.BORROWER; import static org.folio.domain.dto.DcbTransaction.RoleEnum.LENDER; +import static org.folio.domain.dto.DcbTransaction.RoleEnum.PICKUP; import java.util.UUID; @@ -50,7 +51,7 @@ public void createLendingTransaction(EcsTlrEntity ecsTlr) { } @Override - public void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request) { + public void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId) { log.info("createBorrowingTransaction:: creating borrowing transaction for ECS TLR {}", ecsTlr::getId); DcbItem dcbItem = new DcbItem() .id(request.getItemId()) @@ -60,12 +61,29 @@ public void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request) { .requestId(ecsTlr.getPrimaryRequestId().toString()) .item(dcbItem) .role(BORROWER); - final UUID borrowingTransactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); + final UUID borrowingTransactionId = createTransaction(transaction, tenantId); ecsTlr.setPrimaryRequestDcbTransactionId(borrowingTransactionId); log.info("createBorrowingTransaction:: borrowing transaction {} for ECS TLR {} created", () -> borrowingTransactionId, ecsTlr::getId); } + @Override + public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId) { + log.info("createPickupTransaction:: creating borrowing transaction for ECS TLR {}", ecsTlr::getId); + DcbItem dcbItem = new DcbItem() + .id(request.getItemId()) + .title(request.getInstance().getTitle()) + .barcode(request.getItem().getBarcode()); + DcbTransaction transaction = new DcbTransaction() + .requestId(ecsTlr.getPrimaryRequestId().toString()) + .item(dcbItem) + .role(PICKUP); + final UUID transactionId = createTransaction(transaction, tenantId); + ecsTlr.setIntermediateRequestDcbTransactionId(transactionId); + log.info("createPickupTransaction:: pickup transaction {} for ECS TLR {} created", + () -> transactionId, ecsTlr::getId); + } + private UUID createTransaction(DcbTransaction transaction, String tenantId) { final UUID transactionId = UUID.randomUUID(); log.info("createTransaction:: creating transaction {} in tenant {}", transactionId, tenantId); diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 86af9ed8..91ba8c41 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -32,6 +32,7 @@ public class EcsTlrServiceImpl implements EcsTlrService { private final TenantService tenantService; private final RequestService requestService; private final DcbService dcbService; + private final UserTenantsServiceImpl userTenantsService; @Override public Optional get(UUID id) { @@ -47,23 +48,53 @@ public EcsTlr create(EcsTlr ecsTlrDto) { ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); final EcsTlrEntity ecsTlr = requestsMapper.mapDtoToEntity(ecsTlrDto); - String borrowingTenantId = getBorrowingTenant(ecsTlr); - Collection lendingTenantIds = getLendingTenants(ecsTlr); - RequestWrapper secondaryRequest = requestService.createSecondaryRequest( - buildSecondaryRequest(ecsTlr), borrowingTenantId, lendingTenantIds); - - log.info("create:: Creating circulation item for ECS TLR (ILR) {}", ecsTlrDto.getId()); - CirculationItem circulationItem = requestService.createCirculationItem(ecsTlr, - secondaryRequest.request(), borrowingTenantId, secondaryRequest.tenantId()); - + String primaryRequestTenantId = getPrimaryRequestTenant(ecsTlr); + Collection secondaryRequestsTenantIds = getSecondaryRequestTenants(ecsTlr); + + log.info("create:: Creating secondary request for ECS TLR (ILR) {}", ecsTlrDto.getId()); + RequestWrapper secondaryRequestWrapper = requestService.createSecondaryRequest( + buildSecondaryRequest(ecsTlr), primaryRequestTenantId, secondaryRequestsTenantIds); + Request secondaryRequest = secondaryRequestWrapper.request(); + String secondaryRequestTenantId = secondaryRequestWrapper.tenantId(); + + log.info("create:: Creating circulation item for ECS TLR (ILR) {} in the primary request tenant", ecsTlrDto.getId()); + CirculationItem circulationItem = requestService.createCirculationItem( + secondaryRequest.getItemId(), secondaryRequest.getInstanceId(), + secondaryRequest.getPickupServicePointId(), primaryRequestTenantId, + secondaryRequestTenantId); + + log.info("create:: Creating primary request for ECS TLR (ILR) {}", ecsTlrDto.getId()); RequestWrapper primaryRequest = requestService.createPrimaryRequest( - buildPrimaryRequest(secondaryRequest.request()), borrowingTenantId); + buildPrimaryRequest(secondaryRequest), primaryRequestTenantId); + log.info("create:: Updating circulation item for ECS TLR (ILR) {}", ecsTlrDto.getId()); requestService.updateCirculationItemOnRequestCreation(circulationItem, - secondaryRequest.request()); + secondaryRequest); + + updateEcsTlr(ecsTlr, primaryRequest, secondaryRequestWrapper); - updateEcsTlr(ecsTlr, primaryRequest, secondaryRequest); - createDcbTransactions(ecsTlr, secondaryRequest.request()); + var centralTenantId = userTenantsService.getCentralTenantId(); + RequestWrapper intermediateRequest = null; + if (!primaryRequestTenantId.equals(centralTenantId)) { + log.info("create:: Primary request tenant is not central, creating intermediate request"); + + log.info("create:: Creating circulation item for ECS TLR (ILR) {} in the central tenant", ecsTlrDto.getId()); + CirculationItem centralTenantCirculationItem = requestService.createCirculationItem( + secondaryRequest.getItemId(), secondaryRequest.getInstanceId(), + secondaryRequest.getPickupServicePointId(), centralTenantId, + secondaryRequestTenantId); + + log.info("create:: Creating intermediate request for ECS TLR (ILR) {}", ecsTlrDto.getId()); + intermediateRequest = requestService.createPrimaryRequest( + buildPrimaryRequest(secondaryRequest), primaryRequestTenantId); + + log.info("create:: Updating circulation item for ECS TLR (ILR) {}", ecsTlrDto.getId()); + requestService.updateCirculationItemOnRequestCreation(centralTenantCirculationItem, + secondaryRequest); + } + + createDcbTransactions(ecsTlr, secondaryRequest, + intermediateRequest == null ? null : intermediateRequest.request(), centralTenantId); return requestsMapper.mapEntityToDto(save(ecsTlr)); } @@ -90,25 +121,25 @@ public boolean delete(UUID requestId) { return false; } - private String getBorrowingTenant(EcsTlrEntity ecsTlr) { - log.info("getBorrowingTenant:: getting borrowing tenant"); - final String borrowingTenantId = tenantService.getBorrowingTenant(ecsTlr) + private String getPrimaryRequestTenant(EcsTlrEntity ecsTlr) { + log.info("getPrimaryRequestTenant:: getting primary request tenant"); + final String primaryRequestTenantId = tenantService.getPrimaryRequestTenantId(ecsTlr) .orElseThrow(() -> new TenantPickingException("Failed to get borrowing tenant")); - log.info("getBorrowingTenant:: borrowing tenant: {}", borrowingTenantId); + log.info("getPrimaryRequestTenant:: primary request tenant: {}", primaryRequestTenantId); - return borrowingTenantId; + return primaryRequestTenantId; } - private Collection getLendingTenants(EcsTlrEntity ecsTlr) { + private Collection getSecondaryRequestTenants(EcsTlrEntity ecsTlr) { final String instanceId = ecsTlr.getInstanceId().toString(); - log.info("getLendingTenants:: looking for lending tenants for instance {}", instanceId); - List tenantIds = tenantService.getLendingTenants(ecsTlr); + log.info("getSecondaryRequestTenants:: looking for secondary request tenants for instance {}", instanceId); + List tenantIds = tenantService.getSecondaryRequestTenants(ecsTlr); if (tenantIds.isEmpty()) { - log.error("getLendingTenants:: failed to find lending tenants for instance: {}", instanceId); - throw new TenantPickingException("Failed to find lending tenants for instance " + instanceId); + log.error("getSecondaryRequestTenants:: failed to find lending tenants for instance: {}", instanceId); + throw new TenantPickingException("Failed to find secondary request tenants for instance " + instanceId); } - log.info("getLendingTenants:: lending tenants found: {}", tenantIds); + log.info("getSecondaryRequestTenants:: secondary request tenants found: {}", tenantIds); return tenantIds; } @@ -159,13 +190,29 @@ private static void updateEcsTlr(EcsTlrEntity ecsTlr, RequestWrapper primaryRequ log.debug("updateEcsTlr:: ECS TLR: {}", () -> ecsTlr); } - private void createDcbTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest) { + private void createDcbTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest, + Request intermediateRequest, String centralTenantId) { + if (secondaryRequest.getItemId() == null) { log.info("createDcbTransactions:: secondary request has no item ID"); return; } - dcbService.createBorrowingTransaction(ecsTlr, secondaryRequest); - dcbService.createLendingTransaction(ecsTlr); + + if (intermediateRequest == null) { + log.info("createDcbTransactions:: intermediateRequest is null"); + dcbService.createBorrowingTransaction(ecsTlr, secondaryRequest, ecsTlr.getPrimaryRequestTenantId()); + log.info("createDcbTransactions:: Creating lending transaction"); + dcbService.createLendingTransaction(ecsTlr); + } else { + log.info("createDcbTransactions:: intermediateRequest is not null. " + + "Creating borrowing transaction in the central tenant"); + dcbService.createBorrowingTransaction(ecsTlr, secondaryRequest, centralTenantId); + log.info("createDcbTransactions:: Creating lending transaction"); + dcbService.createLendingTransaction(ecsTlr); + log.info("createDcbTransactions:: Creating pickup transaction in tenant {}", + ecsTlr.getPrimaryRequestTenantId()); + dcbService.createPickupTransaction(ecsTlr, secondaryRequest, ecsTlr.getPrimaryRequestTenantId()); + } } } diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java index 770c28a7..ff9aa7ea 100644 --- a/src/main/java/org/folio/service/impl/RequestEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java @@ -151,8 +151,9 @@ private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) { log.info("processItemIdUpdate:: updating ECS TLR {} with itemId {}", ecsTlr::getId, updatedRequest::getItemId); ecsTlr.setItemId(UUID.fromString(updatedRequest.getItemId())); + // TODO: change this if Page request works dcbService.createLendingTransaction(ecsTlr); - dcbService.createBorrowingTransaction(ecsTlr, updatedRequest); + dcbService.createBorrowingTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); ecsTlrRepository.save(ecsTlr); log.info("processItemIdUpdate: ECS TLR {} is updated", ecsTlr::getId); } diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index 6011845a..53dedc42 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -22,9 +22,9 @@ import org.folio.domain.dto.Request; import org.folio.domain.dto.ServicePoint; import org.folio.domain.dto.User; -import org.folio.domain.entity.EcsTlrEntity; import org.folio.exception.RequestCreatingException; import org.folio.service.CloningService; +import org.folio.service.ConsortiaService; import org.folio.service.RequestService; import org.folio.service.ServicePointService; import org.folio.service.UserService; @@ -50,85 +50,83 @@ public class RequestServiceImpl implements RequestService { private final ServicePointService servicePointService; private final CloningService userCloningService; private final CloningService servicePointCloningService; + private final ConsortiaService consortiaService; + private final UserTenantsServiceImpl userTenantsService; private final SystemUserScopedExecutionService systemUserScopedExecutionService; public static final String HOLDINGS_RECORD_ID = "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9"; @Override - public RequestWrapper createPrimaryRequest(Request request, String borrowingTenantId) { + public RequestWrapper createPrimaryRequest(Request request, String primaryRequestTenantId) { final String requestId = request.getId(); - log.info("createPrimaryRequest:: creating primary request {} in borrowing tenant ({})", - requestId, borrowingTenantId); - Request primaryRequest = executionService.executeSystemUserScoped(borrowingTenantId, + log.info("createPrimaryRequest:: creating primary request {} in tenant ({})", + requestId, primaryRequestTenantId); + Request primaryRequest = executionService.executeSystemUserScoped(primaryRequestTenantId, () -> circulationClient.createRequest(request)); - log.info("createPrimaryRequest:: primary request {} created in borrowing tenant ({})", - requestId, borrowingTenantId); + log.info("createPrimaryRequest:: primary request {} created in tenant ({})", + requestId, primaryRequestTenantId); log.debug("createPrimaryRequest:: primary request: {}", () -> primaryRequest); - return new RequestWrapper(primaryRequest, borrowingTenantId); + return new RequestWrapper(primaryRequest, primaryRequestTenantId); } @Override - public RequestWrapper createSecondaryRequest(Request request, String borrowingTenantId, - Collection lendingTenantIds) { + public RequestWrapper createSecondaryRequest(Request request, String primaryRequestTenantId, + Collection secondaryRequestTenantIds) { final String requestId = request.getId(); final String requesterId = request.getRequesterId(); final String pickupServicePointId = request.getPickupServicePointId(); log.info("createSecondaryRequest:: creating secondary request {} in one of potential " + - "lending tenants: {}", requestId, lendingTenantIds); + "tenants: {}", requestId, secondaryRequestTenantIds); - User primaryRequestRequester = executionService.executeSystemUserScoped(borrowingTenantId, + User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId, () -> userService.find(requesterId)); ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped( - borrowingTenantId, () -> servicePointService.find(pickupServicePointId)); + primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId)); - for (String lendingTenantId : lendingTenantIds) { + for (String secondaryRequestTenantId : secondaryRequestTenantIds) { try { - return executionService.executeSystemUserScoped(lendingTenantId, () -> { - log.info("createSecondaryRequest:: creating requester {} in lending tenant ({})", - requesterId, lendingTenantId); + return executionService.executeSystemUserScoped(secondaryRequestTenantId, () -> { + log.info("createSecondaryRequest:: creating requester {} in tenant ({})", + requesterId, secondaryRequestTenantId); cloneRequester(primaryRequestRequester); - log.info("createSecondaryRequest:: creating pickup service point {} in lending tenant ({})", - pickupServicePointId, lendingTenantId); + log.info("createSecondaryRequest:: creating pickup service point {} in tenant ({})", + pickupServicePointId, secondaryRequestTenantId); servicePointCloningService.clone(primaryRequestPickupServicePoint); - log.info("createSecondaryRequest:: creating secondary request {} in lending tenant ({})", - requestId, lendingTenantId); + log.info("createSecondaryRequest:: creating secondary request {} in tenant ({})", + requestId, secondaryRequestTenantId); Request secondaryRequest = circulationClient.createRequest(request); - log.info("createSecondaryRequest:: secondary request {} created in lending tenant ({})", - requestId, lendingTenantId); + log.info("createSecondaryRequest:: secondary request {} created in tenant ({})", + requestId, secondaryRequestTenantId); log.debug("createSecondaryRequest:: secondary request: {}", () -> secondaryRequest); - return new RequestWrapper(secondaryRequest, lendingTenantId); + return new RequestWrapper(secondaryRequest, secondaryRequestTenantId); }); } catch (Exception e) { - log.error("createSecondaryRequest:: failed to create secondary request in lending tenant ({}): {}", - lendingTenantId, e.getMessage()); + log.error("createSecondaryRequest:: failed to create secondary request in tenant ({}): {}", + secondaryRequestTenantId, e.getMessage()); log.debug("createSecondaryRequest:: ", e); } } String errorMessage = format( - "Failed to create secondary request for instance %s in all potential lending tenants: %s", - request.getInstanceId(), lendingTenantIds); + "Failed to create secondary request for instance %s in all potential tenants: %s", + request.getInstanceId(), secondaryRequestTenantIds); log.error("createSecondaryRequest:: {}", errorMessage); throw new RequestCreatingException(errorMessage); } @Override - public CirculationItem createCirculationItem(EcsTlrEntity ecsTlr, Request secondaryRequest, - String borrowingTenantId, String lendingTenantId) { + public CirculationItem createCirculationItem(String itemId, String instanceId, + String pickupLocation, String circulationItemTenantId, String inventoryTenantId) { - if (ecsTlr == null || secondaryRequest == null) { - log.info("createCirculationItem:: ECS TLR or secondary request is null, skipping"); - return null; - } - - var itemId = secondaryRequest.getItemId(); - var instanceId = secondaryRequest.getInstanceId(); + log.info("createCirculationItem:: Creating circulation item, params: itemId={}, " + + "instanceId={}, pickupLocation={}, primaryRequestTenantId={}, secondaryRequestTenantId={}", + itemId, instanceId, pickupLocation, circulationItemTenantId, inventoryTenantId); if (itemId == null || instanceId == null) { log.info("createCirculationItem:: item ID is {}, instance ID is {}, skipping", itemId, instanceId); @@ -142,8 +140,8 @@ public CirculationItem createCirculationItem(EcsTlrEntity ecsTlr, Request second return existingCirculationItem; } - InventoryItem item = getItemFromStorage(itemId, lendingTenantId); - InventoryInstance instance = getInstanceFromStorage(instanceId, lendingTenantId); + InventoryItem item = getItemFromStorage(itemId, inventoryTenantId); + InventoryInstance instance = getInstanceFromStorage(instanceId, inventoryTenantId); var itemStatus = item.getStatus().getName(); var circulationItemStatus = CirculationItemStatus.NameEnum.fromValue(itemStatus.getValue()); @@ -163,13 +161,23 @@ public CirculationItem createCirculationItem(EcsTlrEntity ecsTlr, Request second .permanentLoanTypeId(item.getPermanentLoanTypeId()) .instanceTitle(instance.getTitle()) .barcode(item.getBarcode()) - .pickupLocation(secondaryRequest.getPickupServicePointId()) + .pickupLocation(pickupLocation) .effectiveLocationId(item.getEffectiveLocationId()) .lendingLibraryCode("TEST_CODE"); log.info("createCirculationItem:: Creating circulation item {}", circulationItem.toString()); - return circulationItemClient.createCirculationItem(itemId, circulationItem); + // ? is originating tenant central? + + var centralTenantId = userTenantsService.getCentralTenantId(); + if (circulationItemTenantId.equals(centralTenantId)) { + log.info("createCirculationItem:: Creating circulation item {}", circulationItem.toString()); + // Only create + return circulationItemClient.createCirculationItem(itemId, circulationItem); + } else { + return systemUserScopedExecutionService.executeSystemUserScoped( + circulationItemTenantId, () -> circulationItemClient.createCirculationItem(itemId, circulationItem)); + } } @Override diff --git a/src/main/java/org/folio/service/impl/TenantServiceImpl.java b/src/main/java/org/folio/service/impl/TenantServiceImpl.java index 877a3d8c..7c1b237e 100644 --- a/src/main/java/org/folio/service/impl/TenantServiceImpl.java +++ b/src/main/java/org/folio/service/impl/TenantServiceImpl.java @@ -44,19 +44,19 @@ public class TenantServiceImpl implements TenantService { private final SearchClient searchClient; @Override - public Optional getBorrowingTenant(EcsTlrEntity ecsTlr) { - log.info("getBorrowingTenant:: getting borrowing tenant"); + public Optional getPrimaryRequestTenantId(EcsTlrEntity ecsTlr) { + log.info("getPrimaryRequestTenantId:: getting borrowing tenant"); return HttpUtils.getTenantFromToken(); } @Override - public List getLendingTenants(EcsTlrEntity ecsTlr) { + public List getSecondaryRequestTenants(EcsTlrEntity ecsTlr) { final String instanceId = ecsTlr.getInstanceId().toString(); - log.info("getLendingTenants:: looking for potential lending tenants for instance {}", instanceId); + log.info("getSecondaryRequestTenants:: looking for potential secondary request tenants for instance {}", instanceId); var itemStatusOccurrencesByTenant = getItemStatusOccurrencesByTenant(instanceId); - log.info("getLendingTenants:: item status occurrences by tenant: {}", itemStatusOccurrencesByTenant); + log.info("getSecondaryRequestTenants:: item status occurrences by tenant: {}", itemStatusOccurrencesByTenant); - List lendingTenantIds = itemStatusOccurrencesByTenant.entrySet() + List tenantIds = itemStatusOccurrencesByTenant.entrySet() .stream() .sorted(compareByItemCount(AVAILABLE) .thenComparing(compareByItemCount(CHECKED_OUT, IN_TRANSIT)) @@ -64,13 +64,13 @@ public List getLendingTenants(EcsTlrEntity ecsTlr) { .map(Entry::getKey) .toList(); - if (lendingTenantIds.isEmpty()) { - log.warn("getLendingTenants:: failed to find lending tenants for instance {}", instanceId); + if (tenantIds.isEmpty()) { + log.warn("getSecondaryRequestTenants:: failed to find secondary request tenants for instance {}", instanceId); } else { - log.info("getLendingTenants:: found tenants for instance {}: {}", instanceId, lendingTenantIds); + log.info("getSecondaryRequestTenants:: found tenants for instance {}: {}", instanceId, tenantIds); } - return lendingTenantIds; + return tenantIds; } private Map> getItemStatusOccurrencesByTenant(String instanceId) { diff --git a/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java b/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java index 3192f26d..29e576fe 100644 --- a/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java +++ b/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java @@ -35,5 +35,10 @@ public UserTenant findFirstUserTenant() { log.info("findFirstUserTenant:: result: {}", firstUserTenant); return firstUserTenant; } + + @Override + public String getCentralTenantId() { + return findFirstUserTenant().getCentralTenantId(); + } } diff --git a/src/main/resources/db/changelog/changelog-master.xml b/src/main/resources/db/changelog/changelog-master.xml index 23e9c561..e2754435 100644 --- a/src/main/resources/db/changelog/changelog-master.xml +++ b/src/main/resources/db/changelog/changelog-master.xml @@ -6,4 +6,5 @@ + diff --git a/src/main/resources/db/changelog/changes/2024-10-03-add-intermediate-phase-columns.xml b/src/main/resources/db/changelog/changes/2024-10-03-add-intermediate-phase-columns.xml new file mode 100644 index 00000000..04a65c6c --- /dev/null +++ b/src/main/resources/db/changelog/changes/2024-10-03-add-intermediate-phase-columns.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/swagger.api/schemas/EcsTlr.yaml b/src/main/resources/swagger.api/schemas/EcsTlr.yaml index f9763b8b..a8424fef 100644 --- a/src/main/resources/swagger.api/schemas/EcsTlr.yaml +++ b/src/main/resources/swagger.api/schemas/EcsTlr.yaml @@ -61,6 +61,15 @@ EcsTlr: secondaryRequestTenantId: description: "ID of the tenant secondary request was created in" type: string + intermediateRequestId: + description: "Intermediate request ID" + $ref: "uuid.yaml" + intermediateRequestDcbTransactionId: + description: "ID of DCB transaction created for intermediate request" + $ref: "uuid.yaml" + intermediateRequestTenantId: + description: "ID of the tenant intermediate request was created in" + type: string required: - instanceId diff --git a/src/test/java/org/folio/service/EcsTlrServiceTest.java b/src/test/java/org/folio/service/EcsTlrServiceTest.java index 625d891a..613ec3e5 100644 --- a/src/test/java/org/folio/service/EcsTlrServiceTest.java +++ b/src/test/java/org/folio/service/EcsTlrServiceTest.java @@ -101,9 +101,9 @@ void ecsTlrShouldBeCreatedThenUpdatedAndDeleted(EcsTlr.RequestLevelEnum requestL .itemId(UUID.randomUUID().toString()); when(ecsTlrRepository.save(any(EcsTlrEntity.class))).thenReturn(mockEcsTlrEntity); - when(tenantService.getBorrowingTenant(any(EcsTlrEntity.class))) + when(tenantService.getPrimaryRequestTenantId(any(EcsTlrEntity.class))) .thenReturn(Optional.of(borrowingTenant)); - when(tenantService.getLendingTenants(any(EcsTlrEntity.class))) + when(tenantService.getSecondaryRequestTenants(any(EcsTlrEntity.class))) .thenReturn(List.of(lendingTenant)); when(requestService.createPrimaryRequest(any(Request.class), any(String.class))) .thenReturn(new RequestWrapper(primaryRequest, borrowingTenant)); @@ -135,7 +135,7 @@ void ecsTlrShouldBeCreatedThenUpdatedAndDeleted(EcsTlr.RequestLevelEnum requestL void canNotCreateEcsTlrWhenFailedToGetBorrowingTenantId() { String instanceId = UUID.randomUUID().toString(); EcsTlr ecsTlr = new EcsTlr().instanceId(instanceId); - when(tenantService.getBorrowingTenant(any(EcsTlrEntity.class))) + when(tenantService.getPrimaryRequestTenantId(any(EcsTlrEntity.class))) .thenReturn(Optional.empty()); TenantPickingException exception = assertThrows(TenantPickingException.class, @@ -148,9 +148,9 @@ void canNotCreateEcsTlrWhenFailedToGetBorrowingTenantId() { void canNotCreateEcsTlrWhenFailedToGetLendingTenants() { String instanceId = UUID.randomUUID().toString(); EcsTlr ecsTlr = new EcsTlr().instanceId(instanceId); - when(tenantService.getBorrowingTenant(any(EcsTlrEntity.class))) + when(tenantService.getPrimaryRequestTenantId(any(EcsTlrEntity.class))) .thenReturn(Optional.of("borrowing_tenant")); - when(tenantService.getLendingTenants(any(EcsTlrEntity.class))) + when(tenantService.getSecondaryRequestTenants(any(EcsTlrEntity.class))) .thenReturn(emptyList()); TenantPickingException exception = assertThrows(TenantPickingException.class, diff --git a/src/test/java/org/folio/service/RequestServiceTest.java b/src/test/java/org/folio/service/RequestServiceTest.java index 782d1bbb..520fc071 100644 --- a/src/test/java/org/folio/service/RequestServiceTest.java +++ b/src/test/java/org/folio/service/RequestServiceTest.java @@ -55,53 +55,53 @@ void setUp() { any(Runnable.class)); } - @Test - void shouldReturnNullIfEcsTlrOrSecondaryRequestIsNull() { - assertNull(requestService.createCirculationItem(null, secondaryRequest, BORROWER_ID, LENDER_ID)); - assertNull(requestService.createCirculationItem(ecsTlrEntity, null, BORROWER_ID, LENDER_ID)); - } - - @Test - void shouldReturnNullIfItemIdOrInstanceIdIsNull() { - secondaryRequest.setItemId(null); - assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); - - secondaryRequest.setItemId(ITEM_ID); - secondaryRequest.setInstanceId(null); - assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); - } - - @Test - void shouldReturnExistingCirculationItemIfFound() { - CirculationItem existingItem = new CirculationItem(); - when(circulationItemClient.getCirculationItem(any())).thenReturn(existingItem); - - assertEquals(existingItem, requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); - } - - @Test - void shouldCreateCirculationItem() { - when(circulationItemClient.getCirculationItem(any())).thenReturn(null); - when(circulationItemClient.createCirculationItem(any(), any())).thenReturn(new CirculationItem()); - - InventoryItem item = new InventoryItem(); - item.setStatus(new InventoryItemStatus((InventoryItemStatus.NameEnum.PAGED))); - when(requestService.getItemFromStorage(eq(ITEM_ID), anyString())).thenReturn(item); - - String instanceTitle = "Title"; - InventoryInstance instance = new InventoryInstance(); - instance.setTitle(instanceTitle); - when(requestService.getInstanceFromStorage(eq(INSTANCE_ID), anyString())).thenReturn(instance); - - CirculationItem expectedCirculationItem = new CirculationItem() - .status(new CirculationItemStatus() - .name(CirculationItemStatus.NameEnum.AVAILABLE)) - .id(UUID.fromString(ITEM_ID)) - .holdingsRecordId(UUID.fromString(HOLDINGS_RECORD_ID)) - .dcbItem(true) - .instanceTitle(instanceTitle) - .lendingLibraryCode(LENDING_LIBRARY_CODE); - requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID); - verify(circulationItemClient).createCirculationItem(ITEM_ID, expectedCirculationItem); - } +// @Test +// void shouldReturnNullIfEcsTlrOrSecondaryRequestIsNull() { +// assertNull(requestService.createCirculationItem(null, secondaryRequest, BORROWER_ID, LENDER_ID)); +// assertNull(requestService.createCirculationItem(ecsTlrEntity, null, BORROWER_ID, LENDER_ID)); +// } +// +// @Test +// void shouldReturnNullIfItemIdOrInstanceIdIsNull() { +// secondaryRequest.setItemId(null); +// assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); +// +// secondaryRequest.setItemId(ITEM_ID); +// secondaryRequest.setInstanceId(null); +// assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); +// } +// +// @Test +// void shouldReturnExistingCirculationItemIfFound() { +// CirculationItem existingItem = new CirculationItem(); +// when(circulationItemClient.getCirculationItem(any())).thenReturn(existingItem); +// +// assertEquals(existingItem, requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); +// } +// +// @Test +// void shouldCreateCirculationItem() { +// when(circulationItemClient.getCirculationItem(any())).thenReturn(null); +// when(circulationItemClient.createCirculationItem(any(), any())).thenReturn(new CirculationItem()); +// +// InventoryItem item = new InventoryItem(); +// item.setStatus(new InventoryItemStatus((InventoryItemStatus.NameEnum.PAGED))); +// when(requestService.getItemFromStorage(eq(ITEM_ID), anyString())).thenReturn(item); +// +// String instanceTitle = "Title"; +// InventoryInstance instance = new InventoryInstance(); +// instance.setTitle(instanceTitle); +// when(requestService.getInstanceFromStorage(eq(INSTANCE_ID), anyString())).thenReturn(instance); +// +// CirculationItem expectedCirculationItem = new CirculationItem() +// .status(new CirculationItemStatus() +// .name(CirculationItemStatus.NameEnum.AVAILABLE)) +// .id(UUID.fromString(ITEM_ID)) +// .holdingsRecordId(UUID.fromString(HOLDINGS_RECORD_ID)) +// .dcbItem(true) +// .instanceTitle(instanceTitle) +// .lendingLibraryCode(LENDING_LIBRARY_CODE); +// requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID); +// verify(circulationItemClient).createCirculationItem(ITEM_ID, expectedCirculationItem); +// } } diff --git a/src/test/java/org/folio/service/TenantServiceTest.java b/src/test/java/org/folio/service/TenantServiceTest.java index 4b45ab45..c380c8b0 100644 --- a/src/test/java/org/folio/service/TenantServiceTest.java +++ b/src/test/java/org/folio/service/TenantServiceTest.java @@ -41,7 +41,7 @@ void getLendingTenants(List expectedTenantIds, SearchInstance instance) .thenReturn(new SearchInstancesResponse().instances(singletonList(instance))); EcsTlrEntity ecsTlr = new EcsTlrEntity(); ecsTlr.setInstanceId(INSTANCE_ID); - assertEquals(expectedTenantIds, tenantService.getLendingTenants(ecsTlr)); + assertEquals(expectedTenantIds, tenantService.getSecondaryRequestTenants(ecsTlr)); } private static Stream parametersForGetLendingTenants() { From a3e15f4bce6b1a021ab5e00d2f5c5d7775c6216d Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Tue, 8 Oct 2024 14:20:05 +0300 Subject: [PATCH 02/30] MODTLR-77 Reduce logging --- .../org/folio/service/impl/EcsTlrServiceImpl.java | 5 ++++- .../impl/RequestBatchUpdateEventHandler.java | 14 +++++++------- .../folio/service/impl/UserTenantsServiceImpl.java | 1 - 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 91ba8c41..2addb27f 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; import org.folio.domain.RequestWrapper; import org.folio.domain.dto.CirculationItem; @@ -49,7 +50,9 @@ public EcsTlr create(EcsTlr ecsTlrDto) { final EcsTlrEntity ecsTlr = requestsMapper.mapDtoToEntity(ecsTlrDto); String primaryRequestTenantId = getPrimaryRequestTenant(ecsTlr); - Collection secondaryRequestsTenantIds = getSecondaryRequestTenants(ecsTlr); + Collection secondaryRequestsTenantIds = getSecondaryRequestTenants(ecsTlr).stream() + .filter(tenantId -> !tenantId.equals(primaryRequestTenantId)) + .collect(Collectors.toList()); log.info("create:: Creating secondary request for ECS TLR (ILR) {}", ecsTlrDto.getId()); RequestWrapper secondaryRequestWrapper = requestService.createSecondaryRequest( diff --git a/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java b/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java index a6f2f2d3..2ce021b5 100644 --- a/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java @@ -61,14 +61,14 @@ private void updateQueuePositionsForItemLevel(String itemId) { } private void updateQueuePositions(List unifiedQueue, boolean isTlrRequestQueue) { - log.info("updateQueuePositions:: parameters unifiedQueue: {}", unifiedQueue); + log.debug("updateQueuePositions:: parameters unifiedQueue: {}", unifiedQueue); List sortedPrimaryRequestIds = unifiedQueue.stream() .filter(request -> PRIMARY == request.getEcsRequestPhase()) .filter(request -> request.getPosition() != null) .sorted(Comparator.comparing(Request::getPosition)) .map(request -> UUID.fromString(request.getId())) .toList(); - log.info("updateQueuePositions:: sortedPrimaryRequestIds: {}", sortedPrimaryRequestIds); + log.debug("updateQueuePositions:: sortedPrimaryRequestIds: {}", sortedPrimaryRequestIds); List ecsTlrByPrimaryRequests = ecsTlrRepository.findByPrimaryRequestIdIn( sortedPrimaryRequestIds); @@ -101,7 +101,7 @@ private Map> groupSecondaryRequestsByTenantId( private List sortEcsTlrEntities(List sortedPrimaryRequestIds, List ecsTlrQueue) { - log.info("sortEcsTlrEntities:: parameters sortedPrimaryRequestIds: {}, ecsTlrQueue: {}", + log.debug("sortEcsTlrEntities:: parameters sortedPrimaryRequestIds: {}, ecsTlrQueue: {}", sortedPrimaryRequestIds, ecsTlrQueue); Map ecsTlrByPrimaryRequestId = ecsTlrQueue.stream() .collect(toMap(EcsTlrEntity::getPrimaryRequestId, Function.identity())); @@ -109,7 +109,7 @@ private List sortEcsTlrEntities(List sortedPrimaryRequestIds .stream() .map(ecsTlrByPrimaryRequestId::get) .toList(); - log.info("sortEcsTlrEntities:: result: {}", sortedEcsTlrQueue); + log.debug("sortEcsTlrEntities:: result: {}", sortedEcsTlrQueue); return sortedEcsTlrQueue; } @@ -118,7 +118,7 @@ private void reorderSecondaryRequestsQueue( Map> groupedSecondaryRequestsByTenantId, List sortedEcsTlrQueue, boolean isTlrRequestQueue) { - log.info("reorderSecondaryRequestsQueue:: parameters groupedSecondaryRequestsByTenantId: {}, " + + log.debug("reorderSecondaryRequestsQueue:: parameters groupedSecondaryRequestsByTenantId: {}, " + "sortedEcsTlrQueue: {}", groupedSecondaryRequestsByTenantId, sortedEcsTlrQueue); Map correctOrder = IntStream.range(0, sortedEcsTlrQueue.size()) @@ -198,12 +198,12 @@ private void updateReorderedRequests(List requestsWithUpdatedPositions, new ReorderQueueReorderedQueueInner() .id(request.getId()) .newPosition(request.getPosition()))); - log.info("updateReorderedRequests:: reorderQueue: {}", reorderQueue); + log.debug("updateReorderedRequests:: reorderQueue: {}", reorderQueue); List requests = isTlrRequestQueue ? requestService.reorderRequestsQueueForInstance(id, tenantId, reorderQueue) : requestService.reorderRequestsQueueForItem(id, tenantId, reorderQueue); - log.info("updateReorderedRequests:: result: {}", requests); + log.debug("updateReorderedRequests:: result: {}", requests); } } diff --git a/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java b/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java index 29e576fe..aa632b36 100644 --- a/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java +++ b/src/main/java/org/folio/service/impl/UserTenantsServiceImpl.java @@ -23,7 +23,6 @@ public UserTenant findFirstUserTenant() { log.info("findFirstUserTenant:: finding first userTenant"); UserTenant firstUserTenant = null; UserTenantCollection userTenantCollection = userTenantsClient.getUserTenants(1); - log.info("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection); if (userTenantCollection != null) { log.info("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection); List userTenants = userTenantCollection.getUserTenants(); From e499a5190db3308d0a627cb5e1214fb66fe6f414 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Wed, 13 Nov 2024 22:16:19 +0200 Subject: [PATCH 03/30] MODTLR-77 Valid checksum - ANY --- .../changes/2024-09-05-add-holdings-record-id-column.xml | 1 + src/main/resources/db/changelog/changes/initial_schema.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/resources/db/changelog/changes/2024-09-05-add-holdings-record-id-column.xml b/src/main/resources/db/changelog/changes/2024-09-05-add-holdings-record-id-column.xml index 93cf8955..af73fb5b 100644 --- a/src/main/resources/db/changelog/changes/2024-09-05-add-holdings-record-id-column.xml +++ b/src/main/resources/db/changelog/changes/2024-09-05-add-holdings-record-id-column.xml @@ -5,6 +5,7 @@ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"> + ANY diff --git a/src/main/resources/db/changelog/changes/initial_schema.xml b/src/main/resources/db/changelog/changes/initial_schema.xml index 02f13d2a..696b80d0 100644 --- a/src/main/resources/db/changelog/changes/initial_schema.xml +++ b/src/main/resources/db/changelog/changes/initial_schema.xml @@ -6,6 +6,7 @@ + ANY Create ecs_tlr table From 699e2eddfee08266930abd14c84b048bc015922b Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Wed, 13 Nov 2024 22:36:53 +0200 Subject: [PATCH 04/30] MODTLR-77 Valid checksum - ANY - settings --- src/main/resources/db/changelog/changes/initial_schema.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/db/changelog/changes/initial_schema.xml b/src/main/resources/db/changelog/changes/initial_schema.xml index 696b80d0..aa54ce8c 100644 --- a/src/main/resources/db/changelog/changes/initial_schema.xml +++ b/src/main/resources/db/changelog/changes/initial_schema.xml @@ -37,6 +37,7 @@ + ANY From e209b2eee6a425df5fde0ce3267e39d4c5b5e861 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Thu, 14 Nov 2024 20:04:05 +0200 Subject: [PATCH 05/30] MODTLR-77 Add user-tenants perm --- descriptors/ModuleDescriptor-template.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index a98053c7..c59637ab 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -29,7 +29,8 @@ "users.item.post", "inventory-storage.service-points.item.get", "inventory-storage.service-points.collection.get", - "inventory-storage.service-points.item.post" + "inventory-storage.service-points.item.post", + "user-tenants.collection.get" ] }, { From 741932414521d857e52642719baf16a1a74e5ded Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Fri, 15 Nov 2024 12:33:28 +0200 Subject: [PATCH 06/30] MODTLR-77 Create intermediate request --- .../org/folio/service/RequestService.java | 2 ++ .../folio/service/impl/EcsTlrServiceImpl.java | 32 +++++++++++++------ .../service/impl/RequestServiceImpl.java | 14 +++++++- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/folio/service/RequestService.java b/src/main/java/org/folio/service/RequestService.java index 64237849..1819e4dc 100644 --- a/src/main/java/org/folio/service/RequestService.java +++ b/src/main/java/org/folio/service/RequestService.java @@ -17,6 +17,8 @@ public interface RequestService { RequestWrapper createSecondaryRequest(Request request, String primaryRequestTenantId, Collection secondaryRequestTenantIds); + RequestWrapper createIntermediateRequest(Request request, String intermediateRequestTenantId); + // CirculationItem createCirculationItem(String itemId, String instanceId, // String circulationItemTenantId, String inventoryTenantId); diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 2addb27f..6dc62140 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -1,5 +1,7 @@ package org.folio.service.impl; +import static java.util.Optional.of; + import java.util.Collection; import java.util.List; import java.util.Optional; @@ -54,23 +56,27 @@ public EcsTlr create(EcsTlr ecsTlrDto) { .filter(tenantId -> !tenantId.equals(primaryRequestTenantId)) .collect(Collectors.toList()); - log.info("create:: Creating secondary request for ECS TLR (ILR) {}", ecsTlrDto.getId()); + log.info("create:: Creating secondary request for ECS TLR (ILR), instance {}, item {}, requester {}", + ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); RequestWrapper secondaryRequestWrapper = requestService.createSecondaryRequest( buildSecondaryRequest(ecsTlr), primaryRequestTenantId, secondaryRequestsTenantIds); Request secondaryRequest = secondaryRequestWrapper.request(); String secondaryRequestTenantId = secondaryRequestWrapper.tenantId(); - log.info("create:: Creating circulation item for ECS TLR (ILR) {} in the primary request tenant", ecsTlrDto.getId()); + log.info("create:: Creating circulation item for ECS TLR (ILR) in the primary request tenant {}, instance {}, item {}, requester {}", + primaryRequestTenantId, ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); CirculationItem circulationItem = requestService.createCirculationItem( secondaryRequest.getItemId(), secondaryRequest.getInstanceId(), secondaryRequest.getPickupServicePointId(), primaryRequestTenantId, secondaryRequestTenantId); - log.info("create:: Creating primary request for ECS TLR (ILR) {}", ecsTlrDto.getId()); + log.info("create:: Creating primary request for ECS TLR (ILR), instance {}, item {}, requester {}", + ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); RequestWrapper primaryRequest = requestService.createPrimaryRequest( buildPrimaryRequest(secondaryRequest), primaryRequestTenantId); - log.info("create:: Updating circulation item for ECS TLR (ILR) {}", ecsTlrDto.getId()); + log.info("create:: Updating circulation item for ECS TLR (ILR), instance {}, item {}, requester {}", + ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); requestService.updateCirculationItemOnRequestCreation(circulationItem, secondaryRequest); @@ -81,17 +87,23 @@ public EcsTlr create(EcsTlr ecsTlrDto) { if (!primaryRequestTenantId.equals(centralTenantId)) { log.info("create:: Primary request tenant is not central, creating intermediate request"); - log.info("create:: Creating circulation item for ECS TLR (ILR) {} in the central tenant", ecsTlrDto.getId()); + log.info("create:: Creating circulation item for ECS TLR (ILR) in the central tenant {}, instance {}, item {}, requester {}", + centralTenantId, ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); CirculationItem centralTenantCirculationItem = requestService.createCirculationItem( secondaryRequest.getItemId(), secondaryRequest.getInstanceId(), secondaryRequest.getPickupServicePointId(), centralTenantId, secondaryRequestTenantId); - log.info("create:: Creating intermediate request for ECS TLR (ILR) {}", ecsTlrDto.getId()); - intermediateRequest = requestService.createPrimaryRequest( - buildPrimaryRequest(secondaryRequest), primaryRequestTenantId); + log.info("create:: Creating intermediate request for ECS TLR (ILR), instance {}, item {}, requester {}", + ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); + intermediateRequest = requestService.createIntermediateRequest( + buildPrimaryRequest(secondaryRequest), centralTenantId); - log.info("create:: Updating circulation item for ECS TLR (ILR) {}", ecsTlrDto.getId()); + log.info("create:: Intermediate request {} created, updating circulation item", + of(intermediateRequest) + .map(RequestWrapper::request) + .map(Request::getId) + .orElse(null)); requestService.updateCirculationItemOnRequestCreation(centralTenantCirculationItem, secondaryRequest); } @@ -184,7 +196,7 @@ private static void updateEcsTlr(EcsTlrEntity ecsTlr, RequestWrapper primaryRequ ecsTlr.setPrimaryRequestId(UUID.fromString(primaryRequest.request().getId())); ecsTlr.setSecondaryRequestId(UUID.fromString(secondaryRequest.request().getId())); - Optional.of(secondaryRequest.request()) + of(secondaryRequest.request()) .map(Request::getItemId) .map(UUID::fromString) .ifPresent(ecsTlr::setItemId); diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index dca50922..ee6f5fb0 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -104,7 +104,7 @@ public RequestWrapper createSecondaryRequest(Request request, String primaryRequ requestId, secondaryRequestTenantId); Request secondaryRequest = circulationClient.createRequest(request); log.info("createSecondaryRequest:: secondary request {} created in tenant ({})", - requestId, secondaryRequestTenantId); + secondaryRequest.getId(), secondaryRequestTenantId); log.debug("createSecondaryRequest:: secondary request: {}", () -> secondaryRequest); return new RequestWrapper(secondaryRequest, secondaryRequestTenantId); @@ -123,6 +123,18 @@ public RequestWrapper createSecondaryRequest(Request request, String primaryRequ throw new RequestCreatingException(errorMessage); } + @Override + public RequestWrapper createIntermediateRequest(Request request, String intermediateRequestTenantId) { + log.info("createIntermediateRequest:: creating intermediate request in tenant {}, instance {}, item {}, requester {}", + intermediateRequestTenantId, request.getInstanceId(), request.getItemId(), request.getRequesterId()); + Request intermediateRequest = executionService.executeSystemUserScoped(intermediateRequestTenantId, + () -> circulationClient.createRequest(request)); + log.info("createIntermediateRequest:: intermediate request created in tenant ({})", intermediateRequestTenantId); + log.info("createIntermediateRequest:: intermediate request: {}", () -> intermediateRequest); + + return new RequestWrapper(intermediateRequest, intermediateRequestTenantId); + } + @Override public CirculationItem createCirculationItem(String itemId, String instanceId, String pickupLocation, String circulationItemTenantId, String inventoryTenantId) { From 94d77a4c31b5ed1918e5be72cf80303c00848340 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Fri, 15 Nov 2024 14:05:06 +0200 Subject: [PATCH 07/30] MODTLR-77 Create user in central --- .../org/folio/service/RequestService.java | 2 +- .../folio/service/impl/EcsTlrServiceImpl.java | 2 +- .../service/impl/RequestServiceImpl.java | 46 ++++++++++++++++--- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/folio/service/RequestService.java b/src/main/java/org/folio/service/RequestService.java index 1819e4dc..b04bf10d 100644 --- a/src/main/java/org/folio/service/RequestService.java +++ b/src/main/java/org/folio/service/RequestService.java @@ -17,7 +17,7 @@ public interface RequestService { RequestWrapper createSecondaryRequest(Request request, String primaryRequestTenantId, Collection secondaryRequestTenantIds); - RequestWrapper createIntermediateRequest(Request request, String intermediateRequestTenantId); + RequestWrapper createIntermediateRequest(Request request, String primaryRequestTenantId, String intermediateRequestTenantId); // CirculationItem createCirculationItem(String itemId, String instanceId, // String circulationItemTenantId, String inventoryTenantId); diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 6dc62140..a8f6b413 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -97,7 +97,7 @@ public EcsTlr create(EcsTlr ecsTlrDto) { log.info("create:: Creating intermediate request for ECS TLR (ILR), instance {}, item {}, requester {}", ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); intermediateRequest = requestService.createIntermediateRequest( - buildPrimaryRequest(secondaryRequest), centralTenantId); + buildPrimaryRequest(secondaryRequest), primaryRequestTenantId, centralTenantId); log.info("create:: Intermediate request {} created, updating circulation item", of(intermediateRequest) diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index ee6f5fb0..5ebe30e9 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -124,15 +124,49 @@ public RequestWrapper createSecondaryRequest(Request request, String primaryRequ } @Override - public RequestWrapper createIntermediateRequest(Request request, String intermediateRequestTenantId) { + public RequestWrapper createIntermediateRequest(Request request, String primaryRequestTenantId, String intermediateRequestTenantId) { log.info("createIntermediateRequest:: creating intermediate request in tenant {}, instance {}, item {}, requester {}", intermediateRequestTenantId, request.getInstanceId(), request.getItemId(), request.getRequesterId()); - Request intermediateRequest = executionService.executeSystemUserScoped(intermediateRequestTenantId, - () -> circulationClient.createRequest(request)); - log.info("createIntermediateRequest:: intermediate request created in tenant ({})", intermediateRequestTenantId); - log.info("createIntermediateRequest:: intermediate request: {}", () -> intermediateRequest); - return new RequestWrapper(intermediateRequest, intermediateRequestTenantId); +// Request intermediateRequest = executionService.executeSystemUserScoped(intermediateRequestTenantId, +// () -> circulationClient.createRequest(request)); + try { + return executionService.executeSystemUserScoped(intermediateRequestTenantId, () -> { + final String requesterId = request.getRequesterId(); + final String pickupServicePointId = request.getPickupServicePointId(); + + User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId, + () -> userService.find(requesterId)); + ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped( + primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId)); + + log.info("createIntermediateRequest:: creating requester {} in tenant ({})", + requesterId, intermediateRequestTenantId); + cloneRequester(primaryRequestRequester); + + log.info("createIntermediateRequest:: creating pickup service point {} in tenant ({})", + pickupServicePointId, intermediateRequestTenantId); + servicePointCloningService.clone(primaryRequestPickupServicePoint); + + log.info("createIntermediateRequest:: creating intermediate request in tenant {}", + intermediateRequestTenantId); + Request intermediateRequest = circulationClient.createRequest(request); + log.info("createIntermediateRequest:: intermediate request created in tenant ({})", intermediateRequestTenantId); + log.info("createIntermediateRequest:: intermediate request: {}", () -> intermediateRequest); + + return new RequestWrapper(intermediateRequest, intermediateRequestTenantId); + }); + } catch (Exception e) { + log.error("createIntermediateRequest:: failed to create secondary request in tenant {}: {}", + intermediateRequestTenantId, e.getMessage()); + log.debug("createSecondaryRequest:: ", e); + } + + String errorMessage = format( + "Failed to create intermediate request for instance %s, item %s, requester %s in tenant %s", + request.getInstanceId(), request.getItemId(), request.getRequesterId(), intermediateRequestTenantId); + log.error("createIntermediateRequest:: {}", errorMessage); + throw new RequestCreatingException(errorMessage); } @Override From 106e58ab243c06798b2faacf25b78a3be657da9a Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Fri, 15 Nov 2024 14:37:19 +0200 Subject: [PATCH 08/30] MODTLR-77 buildIntermediateRequest --- .../folio/service/impl/EcsTlrServiceImpl.java | 17 ++++++++++++++++- .../resources/swagger.api/schemas/request.json | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index a8f6b413..b21752c9 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -97,7 +97,7 @@ public EcsTlr create(EcsTlr ecsTlrDto) { log.info("create:: Creating intermediate request for ECS TLR (ILR), instance {}, item {}, requester {}", ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); intermediateRequest = requestService.createIntermediateRequest( - buildPrimaryRequest(secondaryRequest), primaryRequestTenantId, centralTenantId); + buildIntermediateRequest(secondaryRequest), primaryRequestTenantId, centralTenantId); log.info("create:: Intermediate request {} created, updating circulation item", of(intermediateRequest) @@ -182,6 +182,21 @@ private static Request buildPrimaryRequest(Request secondaryRequest) { .pickupServicePointId(secondaryRequest.getPickupServicePointId()); } + private static Request buildIntermediateRequest(Request secondaryRequest) { + return new Request() + .id(secondaryRequest.getId()) + .instanceId(secondaryRequest.getInstanceId()) + .itemId(secondaryRequest.getItemId()) + .holdingsRecordId(secondaryRequest.getHoldingsRecordId()) + .requesterId(secondaryRequest.getRequesterId()) + .requestDate(secondaryRequest.getRequestDate()) + .requestLevel(secondaryRequest.getRequestLevel()) + .requestType(secondaryRequest.getRequestType()) + .ecsRequestPhase(Request.EcsRequestPhaseEnum.INTERMEDIATE) + .fulfillmentPreference(secondaryRequest.getFulfillmentPreference()) + .pickupServicePointId(secondaryRequest.getPickupServicePointId()); + } + private Request buildSecondaryRequest(EcsTlrEntity ecsTlr) { return requestsMapper.mapEntityToRequest(ecsTlr) .ecsRequestPhase(Request.EcsRequestPhaseEnum.SECONDARY); diff --git a/src/main/resources/swagger.api/schemas/request.json b/src/main/resources/swagger.api/schemas/request.json index 5287d652..d504d41a 100644 --- a/src/main/resources/swagger.api/schemas/request.json +++ b/src/main/resources/swagger.api/schemas/request.json @@ -22,7 +22,7 @@ "ecsRequestPhase": { "description": "Stage in ECS request process, absence of this field means this is a single-tenant request", "type": "string", - "enum": ["Primary", "Secondary"] + "enum": ["Primary", "Secondary", "Intermediate"] }, "requestDate": { "description": "Date the request was made", From 84195fb045bc74a540b43d1c27c1b2e9b469efe0 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Fri, 15 Nov 2024 21:37:13 +0200 Subject: [PATCH 09/30] MODTLR-77 Indentation --- .../service/impl/RequestServiceImpl.java | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index 5ebe30e9..75ef47db 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -131,35 +131,35 @@ public RequestWrapper createIntermediateRequest(Request request, String primaryR // Request intermediateRequest = executionService.executeSystemUserScoped(intermediateRequestTenantId, // () -> circulationClient.createRequest(request)); try { - return executionService.executeSystemUserScoped(intermediateRequestTenantId, () -> { - final String requesterId = request.getRequesterId(); - final String pickupServicePointId = request.getPickupServicePointId(); - - User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId, - () -> userService.find(requesterId)); - ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped( - primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId)); - - log.info("createIntermediateRequest:: creating requester {} in tenant ({})", - requesterId, intermediateRequestTenantId); - cloneRequester(primaryRequestRequester); - - log.info("createIntermediateRequest:: creating pickup service point {} in tenant ({})", - pickupServicePointId, intermediateRequestTenantId); - servicePointCloningService.clone(primaryRequestPickupServicePoint); - - log.info("createIntermediateRequest:: creating intermediate request in tenant {}", - intermediateRequestTenantId); - Request intermediateRequest = circulationClient.createRequest(request); - log.info("createIntermediateRequest:: intermediate request created in tenant ({})", intermediateRequestTenantId); - log.info("createIntermediateRequest:: intermediate request: {}", () -> intermediateRequest); - - return new RequestWrapper(intermediateRequest, intermediateRequestTenantId); - }); + return executionService.executeSystemUserScoped(intermediateRequestTenantId, () -> { + final String requesterId = request.getRequesterId(); + final String pickupServicePointId = request.getPickupServicePointId(); + + User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId, + () -> userService.find(requesterId)); + ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped( + primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId)); + + log.info("createIntermediateRequest:: creating requester {} in tenant ({})", + requesterId, intermediateRequestTenantId); + cloneRequester(primaryRequestRequester); + + log.info("createIntermediateRequest:: creating pickup service point {} in tenant ({})", + pickupServicePointId, intermediateRequestTenantId); + servicePointCloningService.clone(primaryRequestPickupServicePoint); + + log.info("createIntermediateRequest:: creating intermediate request in tenant {}", + intermediateRequestTenantId); + Request intermediateRequest = circulationClient.createRequest(request); + log.info("createIntermediateRequest:: intermediate request created in tenant ({})", intermediateRequestTenantId); + log.info("createIntermediateRequest:: intermediate request: {}", () -> intermediateRequest); + + return new RequestWrapper(intermediateRequest, intermediateRequestTenantId); + }); } catch (Exception e) { - log.error("createIntermediateRequest:: failed to create secondary request in tenant {}: {}", + log.error("createIntermediateRequest:: failed to create intermediate request in tenant {}: {}", intermediateRequestTenantId, e.getMessage()); - log.debug("createSecondaryRequest:: ", e); + log.debug("createIntermediateRequest:: ", e); } String errorMessage = format( From aaf299d9802868c6eaa7323c148a07b767e1eca5 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Sat, 16 Nov 2024 20:14:55 +0200 Subject: [PATCH 10/30] MODTLR-77 Create circ item in the correct tenant --- .../service/impl/RequestEventHandler.java | 1 + .../service/impl/RequestServiceImpl.java | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java index ff9aa7ea..48928e32 100644 --- a/src/main/java/org/folio/service/impl/RequestEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java @@ -154,6 +154,7 @@ private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) { // TODO: change this if Page request works dcbService.createLendingTransaction(ecsTlr); dcbService.createBorrowingTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); + dcbService.createPickupTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); ecsTlrRepository.save(ecsTlr); log.info("processItemIdUpdate: ECS TLR {} is updated", ecsTlr::getId); } diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index 75ef47db..a70f5bf5 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -174,7 +174,7 @@ public CirculationItem createCirculationItem(String itemId, String instanceId, String pickupLocation, String circulationItemTenantId, String inventoryTenantId) { log.info("createCirculationItem:: Creating circulation item, params: itemId={}, " + - "instanceId={}, pickupLocation={}, primaryRequestTenantId={}, secondaryRequestTenantId={}", + "instanceId={}, pickupLocation={}, circulationItemTenantId={}, inventoryTenantId={}", itemId, instanceId, pickupLocation, circulationItemTenantId, inventoryTenantId); if (itemId == null || instanceId == null) { @@ -182,10 +182,13 @@ public CirculationItem createCirculationItem(String itemId, String instanceId, return null; } - // check if circulation item already exists - CirculationItem existingCirculationItem = circulationItemClient.getCirculationItem(itemId); + // Check if circulation item already exists in the tenant we want to create it in + CirculationItem existingCirculationItem = executionService.executeSystemUserScoped( + circulationItemTenantId, () -> circulationItemClient.getCirculationItem(itemId)); if (existingCirculationItem != null) { - log.info("createCirculationItem:: circulation item already exists"); + log.info("createCirculationItem:: circulation item already exists in ten" + + "ant {}", circulationItemTenantId); + return existingCirculationItem; } @@ -214,16 +217,15 @@ public CirculationItem createCirculationItem(String itemId, String instanceId, .effectiveLocationId(item.getEffectiveLocationId()) .lendingLibraryCode("TEST_CODE"); - log.info("createCirculationItem:: Creating circulation item {}", circulationItem.toString()); - - // ? is originating tenant central? - var centralTenantId = userTenantsService.getCentralTenantId(); + if (circulationItemTenantId.equals(centralTenantId)) { - log.info("createCirculationItem:: Creating circulation item {}", circulationItem.toString()); - // Only create + log.info("createCirculationItem:: Creating circulation item {} locally in Central", + circulationItem.toString()); return circulationItemClient.createCirculationItem(itemId, circulationItem); } else { + log.info("createCirculationItem:: Creating circulation item {} in tenant {}", + circulationItem.toString(), circulationItemTenantId); return systemUserScopedExecutionService.executeSystemUserScoped( circulationItemTenantId, () -> circulationItemClient.createCirculationItem(itemId, circulationItem)); } From 22f76612997a2df7f6c7b38ca7d5e040efd9d7f0 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Sat, 16 Nov 2024 23:10:18 +0200 Subject: [PATCH 11/30] MODTLR-77 Always use system user for circ item --- .../service/impl/RequestServiceImpl.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index a70f5bf5..bd93a4bf 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -219,16 +219,21 @@ public CirculationItem createCirculationItem(String itemId, String instanceId, var centralTenantId = userTenantsService.getCentralTenantId(); - if (circulationItemTenantId.equals(centralTenantId)) { - log.info("createCirculationItem:: Creating circulation item {} locally in Central", - circulationItem.toString()); - return circulationItemClient.createCirculationItem(itemId, circulationItem); - } else { - log.info("createCirculationItem:: Creating circulation item {} in tenant {}", - circulationItem.toString(), circulationItemTenantId); - return systemUserScopedExecutionService.executeSystemUserScoped( - circulationItemTenantId, () -> circulationItemClient.createCirculationItem(itemId, circulationItem)); - } + log.info("createCirculationItem:: Creating circulation item {} in tenant {}", + circulationItem.toString(), circulationItemTenantId); + return systemUserScopedExecutionService.executeSystemUserScoped( + circulationItemTenantId, () -> circulationItemClient.createCirculationItem(itemId, circulationItem)); + +// if (circulationItemTenantId.equals(centralTenantId)) { +// log.info("createCirculationItem:: Creating circulation item {} locally in Central", +// circulationItem.toString()); +// return circulationItemClient.createCirculationItem(itemId, circulationItem); +// } else { +// log.info("createCirculationItem:: Creating circulation item {} in tenant {}", +// circulationItem.toString(), circulationItemTenantId); +// return systemUserScopedExecutionService.executeSystemUserScoped( +// circulationItemTenantId, () -> circulationItemClient.createCirculationItem(itemId, circulationItem)); +// } } @Override From f0c607ae0cd43918fcff200aa9f8d19a87711826 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Wed, 20 Nov 2024 23:53:57 +0200 Subject: [PATCH 12/30] MODTLR-77 Get primary tenant ID from body --- .../java/org/folio/service/impl/DcbServiceImpl.java | 2 +- .../org/folio/service/impl/EcsTlrServiceImpl.java | 13 +++++++++++++ .../org/folio/service/impl/TenantServiceImpl.java | 11 +++++++++-- src/main/java/org/folio/util/HttpUtils.java | 2 ++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java index 3691830c..c8480d29 100644 --- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java +++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java @@ -69,7 +69,7 @@ public void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request, Str @Override public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId) { - log.info("createPickupTransaction:: creating borrowing transaction for ECS TLR {}", ecsTlr::getId); + log.info("createPickupTransaction:: creating pickup transaction for ECS TLR {}", ecsTlr.getId()); DcbItem dcbItem = new DcbItem() .id(request.getItemId()) .title(request.getInstance().getTitle()) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index b21752c9..ad0f52a0 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -106,6 +106,8 @@ public EcsTlr create(EcsTlr ecsTlrDto) { .orElse(null)); requestService.updateCirculationItemOnRequestCreation(centralTenantCirculationItem, secondaryRequest); + + updateEcsTlrWithIntermediateRequest(ecsTlr, intermediateRequest); } createDcbTransactions(ecsTlr, secondaryRequest, @@ -220,6 +222,17 @@ private static void updateEcsTlr(EcsTlrEntity ecsTlr, RequestWrapper primaryRequ log.debug("updateEcsTlr:: ECS TLR: {}", () -> ecsTlr); } + private static void updateEcsTlrWithIntermediateRequest(EcsTlrEntity ecsTlr, + RequestWrapper intermediateRequest) { + + log.info("updateEcsTlrWithIntermediateRequest:: updating ECS TLR in memory"); + ecsTlr.setIntermediateRequestTenantId(intermediateRequest.tenantId()); + ecsTlr.setIntermediateRequestId(UUID.fromString(intermediateRequest.request().getId())); + + log.info("updateEcsTlrWithIntermediateRequest:: ECS TLR updated in memory"); + log.debug("updateEcsTlrWithIntermediateRequest:: ECS TLR: {}", () -> ecsTlr); + } + private void createDcbTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest, Request intermediateRequest, String centralTenantId) { diff --git a/src/main/java/org/folio/service/impl/TenantServiceImpl.java b/src/main/java/org/folio/service/impl/TenantServiceImpl.java index 7c1b237e..583fc4ad 100644 --- a/src/main/java/org/folio/service/impl/TenantServiceImpl.java +++ b/src/main/java/org/folio/service/impl/TenantServiceImpl.java @@ -3,6 +3,7 @@ import static com.google.common.base.Predicates.alwaysTrue; import static com.google.common.base.Predicates.notNull; import static java.util.Comparator.comparingLong; +import static java.util.Optional.ofNullable; import static java.util.function.Function.identity; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.counting; @@ -45,8 +46,14 @@ public class TenantServiceImpl implements TenantService { @Override public Optional getPrimaryRequestTenantId(EcsTlrEntity ecsTlr) { - log.info("getPrimaryRequestTenantId:: getting borrowing tenant"); - return HttpUtils.getTenantFromToken(); + log.info("getPrimaryRequestTenantId:: primary tenant ID in the request body: {}", + ecsTlr.getPrimaryRequestTenantId()); + + return ofNullable(ecsTlr.getPrimaryRequestTenantId()) + .or(HttpUtils::getTenantFromToken); + +// log.info("getPrimaryRequestTenantId:: getting borrowing tenant"); +// return HttpUtils.getTenantFromToken(); } @Override diff --git a/src/main/java/org/folio/util/HttpUtils.java b/src/main/java/org/folio/util/HttpUtils.java index f284ee1a..aebfa529 100644 --- a/src/main/java/org/folio/util/HttpUtils.java +++ b/src/main/java/org/folio/util/HttpUtils.java @@ -24,6 +24,7 @@ public class HttpUtils { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static Optional getTenantFromToken() { + log.info("getTenantFromToken:: looking for a token"); return getCurrentRequest() .flatMap(HttpUtils::getToken) .flatMap(HttpUtils::extractTenantFromToken); @@ -37,6 +38,7 @@ public static Optional getCurrentRequest() { } private static Optional getToken(HttpServletRequest request) { + log.info("getToken:: trying to get token from the cookie first, then header"); return getCookie(request, ACCESS_TOKEN_COOKIE_NAME) .or(() -> getHeader(request, XOkapiHeaders.TOKEN)); } From cd3c2696b5e7a612061ac6d557977b2e3ae3f33c Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Wed, 27 Nov 2024 13:40:19 +0200 Subject: [PATCH 13/30] MODTLR-77 Add todo --- src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index ad0f52a0..782e52ac 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -243,7 +243,10 @@ private void createDcbTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest if (intermediateRequest == null) { log.info("createDcbTransactions:: intermediateRequest is null"); + + // TODO: BORROWING PICKUP dcbService.createBorrowingTransaction(ecsTlr, secondaryRequest, ecsTlr.getPrimaryRequestTenantId()); + log.info("createDcbTransactions:: Creating lending transaction"); dcbService.createLendingTransaction(ecsTlr); } else { From 9278bb861715d7d497bb7fa2c69694898c642481 Mon Sep 17 00:00:00 2001 From: alexanderkurash Date: Thu, 28 Nov 2024 00:12:09 +0200 Subject: [PATCH 14/30] MODTLR-98 Create borrowing pickup role --- src/main/java/org/folio/service/DcbService.java | 2 +- src/main/java/org/folio/service/impl/DcbServiceImpl.java | 5 +++-- src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java | 4 ++-- .../java/org/folio/service/impl/RequestEventHandler.java | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/folio/service/DcbService.java b/src/main/java/org/folio/service/DcbService.java index 6aa0a001..cd2488d3 100644 --- a/src/main/java/org/folio/service/DcbService.java +++ b/src/main/java/org/folio/service/DcbService.java @@ -9,7 +9,7 @@ public interface DcbService { void createLendingTransaction(EcsTlrEntity ecsTlr); - void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId); + void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId); void createPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId); TransactionStatusResponse getTransactionStatus(UUID transactionId, String tenantId); TransactionStatusResponse updateTransactionStatus(UUID transactionId, diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java index c8480d29..67663815 100644 --- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java +++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java @@ -1,6 +1,7 @@ package org.folio.service.impl; import static org.folio.domain.dto.DcbTransaction.RoleEnum.BORROWER; +import static org.folio.domain.dto.DcbTransaction.RoleEnum.BORROWING_PICKUP; import static org.folio.domain.dto.DcbTransaction.RoleEnum.LENDER; import static org.folio.domain.dto.DcbTransaction.RoleEnum.PICKUP; @@ -51,7 +52,7 @@ public void createLendingTransaction(EcsTlrEntity ecsTlr) { } @Override - public void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId) { + public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId) { log.info("createBorrowingTransaction:: creating borrowing transaction for ECS TLR {}", ecsTlr::getId); DcbItem dcbItem = new DcbItem() .id(request.getItemId()) @@ -60,7 +61,7 @@ public void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request, Str DcbTransaction transaction = new DcbTransaction() .requestId(ecsTlr.getPrimaryRequestId().toString()) .item(dcbItem) - .role(BORROWER); + .role(BORROWING_PICKUP); final UUID borrowingTransactionId = createTransaction(transaction, tenantId); ecsTlr.setPrimaryRequestDcbTransactionId(borrowingTransactionId); log.info("createBorrowingTransaction:: borrowing transaction {} for ECS TLR {} created", diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 782e52ac..072bda78 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -245,14 +245,14 @@ private void createDcbTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest log.info("createDcbTransactions:: intermediateRequest is null"); // TODO: BORROWING PICKUP - dcbService.createBorrowingTransaction(ecsTlr, secondaryRequest, ecsTlr.getPrimaryRequestTenantId()); + dcbService.createBorrowingPickupTransaction(ecsTlr, secondaryRequest, ecsTlr.getPrimaryRequestTenantId()); log.info("createDcbTransactions:: Creating lending transaction"); dcbService.createLendingTransaction(ecsTlr); } else { log.info("createDcbTransactions:: intermediateRequest is not null. " + "Creating borrowing transaction in the central tenant"); - dcbService.createBorrowingTransaction(ecsTlr, secondaryRequest, centralTenantId); + dcbService.createBorrowingPickupTransaction(ecsTlr, secondaryRequest, centralTenantId); log.info("createDcbTransactions:: Creating lending transaction"); dcbService.createLendingTransaction(ecsTlr); log.info("createDcbTransactions:: Creating pickup transaction in tenant {}", diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java index 48928e32..33651a6a 100644 --- a/src/main/java/org/folio/service/impl/RequestEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java @@ -153,7 +153,7 @@ private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) { ecsTlr.setItemId(UUID.fromString(updatedRequest.getItemId())); // TODO: change this if Page request works dcbService.createLendingTransaction(ecsTlr); - dcbService.createBorrowingTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); + dcbService.createBorrowingPickupTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); dcbService.createPickupTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); ecsTlrRepository.save(ecsTlr); log.info("processItemIdUpdate: ECS TLR {} is updated", ecsTlr::getId); From a7c604632126b5f6e719195c1d8f9c36090d9a31 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Tue, 3 Dec 2024 15:30:03 +0200 Subject: [PATCH 15/30] MODTLR-98 Create transactions with correct roles --- .../java/org/folio/service/DcbService.java | 6 +- .../folio/service/impl/DcbServiceImpl.java | 58 +++++++++++++++---- .../folio/service/impl/EcsTlrServiceImpl.java | 31 +--------- .../service/impl/RequestEventHandler.java | 4 +- 4 files changed, 52 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/folio/service/DcbService.java b/src/main/java/org/folio/service/DcbService.java index cd2488d3..7b8cb372 100644 --- a/src/main/java/org/folio/service/DcbService.java +++ b/src/main/java/org/folio/service/DcbService.java @@ -8,9 +8,11 @@ import org.folio.domain.entity.EcsTlrEntity; public interface DcbService { + void createTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest); void createLendingTransaction(EcsTlrEntity ecsTlr); - void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId); - void createPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId); + void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request); + void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request); + void createPickupTransaction(EcsTlrEntity ecsTlr, Request request); TransactionStatusResponse getTransactionStatus(UUID transactionId, String tenantId); TransactionStatusResponse updateTransactionStatus(UUID transactionId, TransactionStatus.StatusEnum newStatus, String tenantId); diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java index 67663815..d405a5f6 100644 --- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java +++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java @@ -45,15 +45,15 @@ public void createLendingTransaction(EcsTlrEntity ecsTlr) { DcbTransaction transaction = new DcbTransaction() .requestId(ecsTlr.getSecondaryRequestId().toString()) .role(LENDER); - final UUID lendingTransactionId = createTransaction(transaction, ecsTlr.getSecondaryRequestTenantId()); - ecsTlr.setSecondaryRequestDcbTransactionId(lendingTransactionId); + final UUID transactionId = createTransaction(transaction, ecsTlr.getSecondaryRequestTenantId()); + ecsTlr.setSecondaryRequestDcbTransactionId(transactionId); log.info("createTransactions:: lending transaction {} for ECS TLR {} created", - () -> lendingTransactionId, ecsTlr::getId); + () -> transactionId, ecsTlr::getId); } @Override - public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId) { - log.info("createBorrowingTransaction:: creating borrowing transaction for ECS TLR {}", ecsTlr::getId); + public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request) { + log.info("createBorrowingPickupTransaction:: creating borrowing-pickup transaction for ECS TLR {}", ecsTlr::getId); DcbItem dcbItem = new DcbItem() .id(request.getItemId()) .title(request.getInstance().getTitle()) @@ -62,14 +62,31 @@ public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request reques .requestId(ecsTlr.getPrimaryRequestId().toString()) .item(dcbItem) .role(BORROWING_PICKUP); - final UUID borrowingTransactionId = createTransaction(transaction, tenantId); - ecsTlr.setPrimaryRequestDcbTransactionId(borrowingTransactionId); - log.info("createBorrowingTransaction:: borrowing transaction {} for ECS TLR {} created", - () -> borrowingTransactionId, ecsTlr::getId); + final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); + ecsTlr.setPrimaryRequestDcbTransactionId(transactionId); + log.info("createBorrowingPickupTransaction:: borrowing-pickup transaction {} for ECS TLR {} created", + () -> transactionId, ecsTlr::getId); } @Override - public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request, String tenantId) { + public void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request) { + log.info("createBorrowerTransaction:: creating borrower transaction for ECS TLR {}", ecsTlr::getId); + DcbItem dcbItem = new DcbItem() + .id(request.getItemId()) + .title(request.getInstance().getTitle()) + .barcode(request.getItem().getBarcode()); + DcbTransaction transaction = new DcbTransaction() + .requestId(ecsTlr.getIntermediateRequestId().toString()) + .item(dcbItem) + .role(BORROWER); + final UUID transactionId = createTransaction(transaction, ecsTlr.getIntermediateRequestTenantId()); + ecsTlr.setIntermediateRequestDcbTransactionId(transactionId); + log.info("createBorrowerTransaction:: borrower transaction {} for ECS TLR {} created", + () -> transactionId, ecsTlr::getId); + } + + @Override + public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request) { log.info("createPickupTransaction:: creating pickup transaction for ECS TLR {}", ecsTlr.getId()); DcbItem dcbItem = new DcbItem() .id(request.getItemId()) @@ -79,8 +96,8 @@ public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request, String .requestId(ecsTlr.getPrimaryRequestId().toString()) .item(dcbItem) .role(PICKUP); - final UUID transactionId = createTransaction(transaction, tenantId); - ecsTlr.setIntermediateRequestDcbTransactionId(transactionId); + final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); + ecsTlr.setPrimaryRequestDcbTransactionId(transactionId); log.info("createPickupTransaction:: pickup transaction {} for ECS TLR {} created", () -> transactionId, ecsTlr::getId); } @@ -116,4 +133,21 @@ public TransactionStatusResponse updateTransactionStatus(UUID transactionId, transactionId.toString(), new TransactionStatus().status(newStatus))); } + @Override + public void createTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest) { + log.info("createTransactions:: creating transactions for ECS TLR {}", ecsTlr::getId); + if (secondaryRequest.getItemId() == null) { + log.info("createDcbTransactions:: secondary request has no item ID"); + return; + } + createLendingTransaction(ecsTlr); + log.info("createTransactions:: intermediate request ID: {}", ecsTlr::getIntermediateRequestId); + if (ecsTlr.getIntermediateRequestId() == null) { + createBorrowingPickupTransaction(ecsTlr, secondaryRequest); + } else { + createBorrowerTransaction(ecsTlr, secondaryRequest); + createPickupTransaction(ecsTlr, secondaryRequest); + } + } + } diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 0c0d9d56..43ddd392 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -110,8 +110,7 @@ public EcsTlr create(EcsTlr ecsTlrDto) { updateEcsTlrWithIntermediateRequest(ecsTlr, intermediateRequest); } - createDcbTransactions(ecsTlr, secondaryRequest, - intermediateRequest == null ? null : intermediateRequest.request(), centralTenantId); + dcbService.createTransactions(ecsTlr, secondaryRequest); return requestsMapper.mapEntityToDto(save(ecsTlr)); } @@ -236,32 +235,4 @@ private static void updateEcsTlrWithIntermediateRequest(EcsTlrEntity ecsTlr, log.debug("updateEcsTlrWithIntermediateRequest:: ECS TLR: {}", () -> ecsTlr); } - private void createDcbTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest, - Request intermediateRequest, String centralTenantId) { - - if (secondaryRequest.getItemId() == null) { - log.info("createDcbTransactions:: secondary request has no item ID"); - return; - } - - if (intermediateRequest == null) { - log.info("createDcbTransactions:: intermediateRequest is null"); - - // TODO: BORROWING PICKUP - dcbService.createBorrowingPickupTransaction(ecsTlr, secondaryRequest, ecsTlr.getPrimaryRequestTenantId()); - - log.info("createDcbTransactions:: Creating lending transaction"); - dcbService.createLendingTransaction(ecsTlr); - } else { - log.info("createDcbTransactions:: intermediateRequest is not null. " + - "Creating borrowing transaction in the central tenant"); - dcbService.createBorrowingPickupTransaction(ecsTlr, secondaryRequest, centralTenantId); - log.info("createDcbTransactions:: Creating lending transaction"); - dcbService.createLendingTransaction(ecsTlr); - log.info("createDcbTransactions:: Creating pickup transaction in tenant {}", - ecsTlr.getPrimaryRequestTenantId()); - dcbService.createPickupTransaction(ecsTlr, secondaryRequest, ecsTlr.getPrimaryRequestTenantId()); - } - } - } diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java index 33651a6a..60e294cb 100644 --- a/src/main/java/org/folio/service/impl/RequestEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java @@ -152,9 +152,7 @@ private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) { updatedRequest::getItemId); ecsTlr.setItemId(UUID.fromString(updatedRequest.getItemId())); // TODO: change this if Page request works - dcbService.createLendingTransaction(ecsTlr); - dcbService.createBorrowingPickupTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); - dcbService.createPickupTransaction(ecsTlr, updatedRequest, ecsTlr.getPrimaryRequestTenantId()); + dcbService.createTransactions(ecsTlr, updatedRequest); ecsTlrRepository.save(ecsTlr); log.info("processItemIdUpdate: ECS TLR {} is updated", ecsTlr::getId); } From ea5a37bddb9c5bde09dae7da27d0715bb4cde591 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Tue, 3 Dec 2024 15:46:44 +0200 Subject: [PATCH 16/30] MODTLR-98 Create transactions with correct roles --- .../folio/service/impl/DcbServiceImpl.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java index d405a5f6..ef9b9482 100644 --- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java +++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java @@ -11,6 +11,7 @@ import org.folio.client.feign.DcbTransactionClient; import org.folio.domain.dto.DcbItem; import org.folio.domain.dto.DcbTransaction; +import org.folio.domain.dto.DcbTransaction.RoleEnum; import org.folio.domain.dto.Request; import org.folio.domain.dto.TransactionStatus; import org.folio.domain.dto.TransactionStatusResponse; @@ -51,23 +52,6 @@ public void createLendingTransaction(EcsTlrEntity ecsTlr) { () -> transactionId, ecsTlr::getId); } - @Override - public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request) { - log.info("createBorrowingPickupTransaction:: creating borrowing-pickup transaction for ECS TLR {}", ecsTlr::getId); - DcbItem dcbItem = new DcbItem() - .id(request.getItemId()) - .title(request.getInstance().getTitle()) - .barcode(request.getItem().getBarcode()); - DcbTransaction transaction = new DcbTransaction() - .requestId(ecsTlr.getPrimaryRequestId().toString()) - .item(dcbItem) - .role(BORROWING_PICKUP); - final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); - ecsTlr.setPrimaryRequestDcbTransactionId(transactionId); - log.info("createBorrowingPickupTransaction:: borrowing-pickup transaction {} for ECS TLR {} created", - () -> transactionId, ecsTlr::getId); - } - @Override public void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request) { log.info("createBorrowerTransaction:: creating borrower transaction for ECS TLR {}", ecsTlr::getId); @@ -85,9 +69,24 @@ public void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request) { () -> transactionId, ecsTlr::getId); } + @Override + public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request) { + log.info("createBorrowingPickupTransaction:: creating borrowing-pickup transaction for ECS TLR {}", + ecsTlr::getId); + final UUID transactionId = createPickupTransaction(ecsTlr, request, BORROWING_PICKUP); + log.info("createBorrowingPickupTransaction:: borrowing-pickup transaction {} for ECS TLR {} created", + () -> transactionId, ecsTlr::getId); + } + @Override public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request) { log.info("createPickupTransaction:: creating pickup transaction for ECS TLR {}", ecsTlr.getId()); + final UUID transactionId = createPickupTransaction(ecsTlr, request, PICKUP); + log.info("createPickupTransaction:: pickup transaction {} for ECS TLR {} created", + () -> transactionId, ecsTlr::getId); + } + + public UUID createPickupTransaction(EcsTlrEntity ecsTlr, Request request, RoleEnum role) { DcbItem dcbItem = new DcbItem() .id(request.getItemId()) .title(request.getInstance().getTitle()) @@ -95,11 +94,11 @@ public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request) { DcbTransaction transaction = new DcbTransaction() .requestId(ecsTlr.getPrimaryRequestId().toString()) .item(dcbItem) - .role(PICKUP); + .role(role); final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); ecsTlr.setPrimaryRequestDcbTransactionId(transactionId); - log.info("createPickupTransaction:: pickup transaction {} for ECS TLR {} created", - () -> transactionId, ecsTlr::getId); + + return transactionId; } private UUID createTransaction(DcbTransaction transaction, String tenantId) { From 0ac48d9c154fb169ba1878413472ee202889232d Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 4 Dec 2024 11:32:51 +0200 Subject: [PATCH 17/30] MODTLR-98 Create transactions with correct roles --- src/main/java/org/folio/service/impl/DcbServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java index ef9b9482..3106baf7 100644 --- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java +++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java @@ -86,7 +86,7 @@ public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request) { () -> transactionId, ecsTlr::getId); } - public UUID createPickupTransaction(EcsTlrEntity ecsTlr, Request request, RoleEnum role) { + private UUID createPickupTransaction(EcsTlrEntity ecsTlr, Request request, RoleEnum role) { DcbItem dcbItem = new DcbItem() .id(request.getItemId()) .title(request.getInstance().getTitle()) From d69f5fd3b2047e289c76dce9b390648fc496b82f Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 4 Dec 2024 11:43:25 +0200 Subject: [PATCH 18/30] MODTLR-98 Remove ``"additionalProperties": false` from request schema --- .../swagger.api/schemas/request.json | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/main/resources/swagger.api/schemas/request.json b/src/main/resources/swagger.api/schemas/request.json index d504d41a..7835af07 100644 --- a/src/main/resources/swagger.api/schemas/request.json +++ b/src/main/resources/swagger.api/schemas/request.json @@ -120,12 +120,7 @@ "description": "UUID of resource identifier type (e.g. ISBN, ISSN, LCCN, CODEN, Locally defined identifiers)", "$ref": "uuid.json" } - }, - "additionalProperties": false, - "required": [ - "value", - "identifierTypeId" - ] + } } } } @@ -138,8 +133,7 @@ "description": "barcode of the item", "type": "string" } - }, - "additionalProperties": false + } }, "requester": { "description": "Copy of some requesting patron metadata (used for searching and sorting), will be taken from the user referred to by the requesterId", @@ -175,7 +169,6 @@ "patronGroup": { "description": "record for the user's patron group", "type": "object", - "additionalProperties": false, "readonly": true, "properties": { "id": { @@ -196,8 +189,7 @@ } } } - }, - "additionalProperties": false + } }, "proxy": { "description": "Copy of some proxy patron metadata (used for searching and sorting), will be taken from the user referred to by the proxyUserId", @@ -234,7 +226,6 @@ "description": "record for the user's patrongroup", "type": "object", "readonly": true, - "additionalProperties": false, "properties": { "id": { "description": "ID of the patrongroup", @@ -254,8 +245,7 @@ } } } - }, - "additionalProperties": false + } }, "fulfillmentPreference": { "description": "How should the request be fulfilled (whether the item should be kept on the hold shelf for collection or delivered to the requester)", @@ -308,8 +298,7 @@ "readonly": true, "$ref": "uuid.json" } - }, - "additionalProperties": false + } }, "requestExpirationDate": { "description": "Date when the request expires", @@ -328,7 +317,6 @@ }, "pickupServicePoint": { "description": "The full object of the Service Point record from pickupServicePointId", - "additionalProperties": false, "readonly": true, "properties": { "name": { @@ -389,12 +377,5 @@ "type": "object", "$ref": "request-search-index.json" } - }, - "additionalProperties": false, - "required": [ - "requesterId", - "requestType", - "requestDate", - "fulfillmentPreference" - ] + } } From 82341bd201ff6792721ee19c1784e48ff8ee29f2 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 4 Dec 2024 12:46:44 +0200 Subject: [PATCH 19/30] MODTLR-98 Do not manage DCB transaction status --- src/main/java/org/folio/service/impl/RequestEventHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java index 60e294cb..c7db1643 100644 --- a/src/main/java/org/folio/service/impl/RequestEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java @@ -183,7 +183,7 @@ private static Optional determineNewTransactionSta ts -> log.info("determineNewTransactionStatus:: new transaction status: {}", ts), () -> log.info("determineNewTransactionStatus:: irrelevant request status change")); - return newTransactionStatus; + return Optional.empty(); } private void updateTransactionStatus(UUID transactionId, From a81a6e5f0035fa830729da662a7dafa104b08a46 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 4 Dec 2024 13:04:26 +0200 Subject: [PATCH 20/30] MODTLR-98 Refresh request schema --- .../swagger.api/schemas/request.json | 293 ++++++------------ 1 file changed, 91 insertions(+), 202 deletions(-) diff --git a/src/main/resources/swagger.api/schemas/request.json b/src/main/resources/swagger.api/schemas/request.json index 7835af07..40de3876 100644 --- a/src/main/resources/swagger.api/schemas/request.json +++ b/src/main/resources/swagger.api/schemas/request.json @@ -1,24 +1,23 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "A request for an item", - "description": "Request for an item that might be at a different location or already checked out to another patron", + "description": "A request by a patron for a specific item", "type": "object", "properties": { "id": { "description": "UUID of the request", "type": "string", - "$ref": "uuid.json" - }, - "requestType": { - "description": "Whether the item should be held upon return, recalled or paged for", - "type": "string", - "enum": ["Hold", "Recall", "Page"] + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" }, "requestLevel": { "description": "Level of the request - Item or Title", "type": "string", "enum": ["Item", "Title"] }, + "requestType": { + "description": "Whether the item should be held upon return, recalled or paged for", + "type": "string", + "enum": ["Hold", "Recall", "Page"] + }, "ecsRequestPhase": { "description": "Stage in ECS request process, absence of this field means this is a single-tenant request", "type": "string", @@ -34,14 +33,14 @@ "type": "string" }, "requesterId": { - "description": "ID of the user who made the request", + "description": "ID of the requesting patron (user)", "type": "string", - "$ref": "uuid.json" + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" }, "proxyUserId": { "description": "ID of the user representing a proxy for the patron", "type": "string", - "$ref": "uuid.json" + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" }, "instanceId": { "description": "ID of the instance being requested", @@ -56,7 +55,7 @@ "itemId": { "description": "ID of the item being requested", "type": "string", - "$ref": "uuid.json" + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" }, "status": { "description": "Status of the request", @@ -73,17 +72,15 @@ ] }, "cancellationReasonId": { - "description": "The id of the request reason", - "type": "string", - "$ref": "uuid.json" + "description": "The id of the relevant request reason", + "type": "string" }, "cancelledByUserId": { "description": "The id of the user that cancelled the request", - "type": "string", - "$ref": "uuid.json" + "type": "string" }, "cancellationAdditionalInformation": { - "description": "Additional information about a cancellation", + "description": "Potential relevant information regarding a cancellation", "type": "string" }, "cancelledDate": { @@ -92,9 +89,8 @@ "format": "date-time" }, "position": { - "description": "position of the request in a per-item request queue", - "type": "integer", - "minimum": 1 + "description": "Position of the request in the unified request queue", + "type": "integer" }, "instance": { "description": "Copy of some instance metadata (used for searching and sorting)", @@ -120,7 +116,12 @@ "description": "UUID of resource identifier type (e.g. ISBN, ISSN, LCCN, CODEN, Locally defined identifiers)", "$ref": "uuid.json" } - } + }, + "additionalProperties": true, + "required": [ + "value", + "identifierTypeId" + ] } } } @@ -133,119 +134,62 @@ "description": "barcode of the item", "type": "string" } - } + }, + "additionalProperties": true }, "requester": { - "description": "Copy of some requesting patron metadata (used for searching and sorting), will be taken from the user referred to by the requesterId", - "readonly": true, + "description": "Copy of some requesting patron metadata (used for searching and sorting)", "type": "object", "properties": { "firstName": { - "description": "first name of the patron (read only, defined by the server)", - "type": "string", - "readonly": true + "description": "first name of the requesting patron", + "type": "string" }, "lastName": { - "description": "last name of the patron (read only, defined by the server)", - "type": "string", - "readonly": true + "description": "last name of the requesting patron", + "type": "string" }, "middleName": { - "description": "middle name of the patron (read only, defined by the server)", - "type": "string", - "readonly": true + "description": "middle name of the requesting patron", + "type": "string" }, "barcode": { - "description": "barcode of the patron (read only, defined by the server)", - "type": "string", - "readonly": true - }, - "patronGroupId": { - "description": "UUID for the patron group that this user belongs to", - "type": "string", - "readonly": true, - "$ref": "uuid.json" + "description": "barcode of the requesting patron", + "type": "string" }, - "patronGroup": { - "description": "record for the user's patron group", - "type": "object", - "readonly": true, - "properties": { - "id": { - "description": "ID of the patron group", - "type": "string", - "readonly": true, - "$ref": "uuid.json" - }, - "group": { - "description": "The unique name of the patron group", - "type": "string", - "readonly": true - }, - "desc": { - "description": "A description of the patron group", - "type": "string", - "readonly": true - } - } + "patronGroup" : { + "description": "DEPRECATED, to be removed in subsequent major version", + "type": "string" } - } + }, + "additionalProperties": true }, "proxy": { - "description": "Copy of some proxy patron metadata (used for searching and sorting), will be taken from the user referred to by the proxyUserId", - "readonly": true, + "description": "Copy of some proxy patron metadata (used for searching and sorting)", "type": "object", "properties": { "firstName": { - "description": "first name of the proxy patron (read only, defined by the server)", - "type": "string", - "readonly": true + "description": "first name of the proxy patron", + "type": "string" }, "lastName": { - "description": "last name of the proxy patron (read only, defined by the server)", - "type": "string", - "readonly": true + "description": "last name of the proxy patron", + "type": "string" }, "middleName": { - "description": "middle name of the proxy patron (read only, defined by the server)", - "type": "string", - "readonly": true + "description": "middle name of the proxy patron", + "type": "string" }, "barcode": { - "description": "barcode of the proxy patron (read only, defined by the server)", - "type": "string", - "readonly": true - }, - "patronGroupId": { - "description": "UUID for the patrongroup that this user belongs to", - "type": "string", - "readonly": true, - "$ref": "uuid.json" + "description": "barcode of the proxy patron", + "type": "string" }, "patronGroup": { - "description": "record for the user's patrongroup", - "type": "object", - "readonly": true, - "properties": { - "id": { - "description": "ID of the patrongroup", - "type": "string", - "readonly": true, - "$ref": "uuid.json" - }, - "group": { - "description": "The unique name of the patrongroup", - "type": "string", - "readonly": true - }, - "desc": { - "description": "A description of the patrongroup", - "type": "string", - "readonly": true - } - } + "description": "DEPRECATED, to be removed in subsequent major version", + "type": "string" } - } + }, + "additionalProperties": true }, "fulfillmentPreference": { "description": "How should the request be fulfilled (whether the item should be kept on the hold shelf for collection or delivered to the requester)", @@ -255,50 +199,7 @@ "deliveryAddressTypeId": { "description": "Deliver to the address of this type, for the requesting patron", "type": "string", - "$ref": "uuid.json" - }, - "deliveryAddress": { - "description": "Address the item is to be delivered to (derived from requester information)", - "type": "object", - "readonly": true, - "properties": { - "addressLine1": { - "description": "Address line 1", - "type": "string", - "readonly": true - }, - "addressLine2": { - "description": "Address line 2", - "type": "string", - "readonly": true - }, - "city": { - "description": "City name", - "type": "string", - "readonly": true - }, - "region": { - "description": "Region", - "type": "string", - "readonly": true - }, - "postalCode": { - "description": "Postal code", - "type": "string", - "readonly": true - }, - "countryId": { - "description": "Country code", - "type": "string", - "readonly": true - }, - "addressTypeId": { - "description": "Type of address (refers to address types)", - "type": "string", - "readonly": true, - "$ref": "uuid.json" - } - } + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" }, "requestExpirationDate": { "description": "Date when the request expires", @@ -313,69 +214,57 @@ "pickupServicePointId": { "description": "The ID of the Service Point where this request can be picked up", "type": "string", - "$ref": "uuid.json" + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" }, - "pickupServicePoint": { - "description": "The full object of the Service Point record from pickupServicePointId", - "readonly": true, - "properties": { - "name": { - "description": "Unique name for the service point", - "type": "string", - "readonly": true - }, - "code": { - "description": "Unique code for the service point", - "type": "string", - "readonly": true - }, - "discoveryDisplayName": { - "description": "Human-readable name for the service point", - "type": "string", - "readonly": true - }, - "description": { - "description": "Description of the service point", - "type": "string", - "readonly": true - }, - "shelvingLagTime": { - "description": "Shelving lag time", - "type": "integer", - "readonly": true - }, - "pickupLocation": { - "description": "Is this service point a pickup location?", - "type": "boolean", - "readonly": true - } - } + "metadata": { + "description": "Metadata about creation and changes to requests, provided by the server (client should not provide)", + "type": "object", + "$ref": "metadata.json" }, "tags": { "type": "object", "description": "Tags", "$ref": "tags.json" }, - "metadata": { - "description": "Metadata about creation and changes to requests, provided by the server (client should not provide)", + "printDetails": { "type": "object", - "$ref": "metadata.json" - }, - "requestProcessingParameters": { - "type": "object", - "description": "Additional parameters used for request processing and discarded afterwards. Not part of request record.", + "description": "PrintDetails", "properties": { - "overrideBlocks": { - "type": "object", - "description": "Blocks to override if user has corresponding permissions", - "$ref": "override-blocks.json" + "printCount": { + "type": "integer", + "description": "Number of times print slip generated." + }, + "requesterId": { + "type": "string", + "description": "UUID of print slip requester." + }, + "isPrinted": { + "type": "boolean", + "description": "Whether print slip was printed in past." + }, + "printEventDate": { + "type": "string", + "format": "date-time", + "description": "Date and time when print slip was generated last time." } - } + }, + "additionalProperties": true + }, + "awaitingPickupRequestClosedDate": { + "description": "A date when the request with awaiting pickup status was closed", + "type": "string", + "format": "date-time", + "readonly" : true }, "searchIndex": { "description": "Request fields used for search", "type": "object", "$ref": "request-search-index.json" + }, + "itemLocationCode": { + "description": "Allow specifying item location when creating title-level requests", + "type": "string" } - } -} + }, + "additionalProperties": true +} \ No newline at end of file From 1c4176424e46af87d2d45db4358d9695a7ebc377 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Thu, 5 Dec 2024 13:13:05 +0200 Subject: [PATCH 21/30] MODTLR-98 Synchronize transaction statuses upon request update --- .../folio/service/impl/EcsTlrServiceImpl.java | 3 +- .../service/impl/RequestEventHandler.java | 51 +++++++++++-------- .../service/impl/RequestServiceImpl.java | 4 +- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 43ddd392..1d41a87a 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -83,7 +83,6 @@ public EcsTlr create(EcsTlr ecsTlrDto) { updateEcsTlr(ecsTlr, primaryRequest, secondaryRequestWrapper); var centralTenantId = userTenantsService.getCentralTenantId(); - RequestWrapper intermediateRequest = null; if (!primaryRequestTenantId.equals(centralTenantId)) { log.info("create:: Primary request tenant is not central, creating intermediate request"); @@ -96,7 +95,7 @@ public EcsTlr create(EcsTlr ecsTlrDto) { log.info("create:: Creating intermediate request for ECS TLR (ILR), instance {}, item {}, requester {}", ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); - intermediateRequest = requestService.createIntermediateRequest( + RequestWrapper intermediateRequest = requestService.createIntermediateRequest( buildIntermediateRequest(secondaryRequest), primaryRequestTenantId, centralTenantId); log.info("create:: Intermediate request {} created, updating circulation item", diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java index c7db1643..fbc5b43b 100644 --- a/src/main/java/org/folio/service/impl/RequestEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java @@ -118,29 +118,12 @@ private static boolean requestMatchesEcsTlr(EcsTlrEntity ecsTlr, Request updated private void handlePrimaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) { propagateChangesFromPrimaryToSecondaryRequest(ecsTlr, event); - determineNewTransactionStatus(event).ifPresent(newTransactionStatus -> { - if (newTransactionStatus == CANCELLED) { - log.info("handlePrimaryRequestUpdate:: cancelling secondary DCB transaction"); - updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newTransactionStatus, - ecsTlr.getSecondaryRequestTenantId()); - } else { - updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newTransactionStatus, - ecsTlr.getPrimaryRequestTenantId()); - } - }); + updateTransactionStatuses(event, ecsTlr); } private void handleSecondaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) { processItemIdUpdate(ecsTlr, event.getData().getNewVersion()); - determineNewTransactionStatus(event).ifPresent(newTransactionStatus -> { - updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newTransactionStatus, - ecsTlr.getSecondaryRequestTenantId()); - if (newTransactionStatus == OPEN) { - log.info("handleSecondaryRequestUpdate:: open primary DCB transaction"); - updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newTransactionStatus, - ecsTlr.getPrimaryRequestTenantId()); - } - }); + updateTransactionStatuses(event, ecsTlr); } private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) { @@ -183,12 +166,40 @@ private static Optional determineNewTransactionSta ts -> log.info("determineNewTransactionStatus:: new transaction status: {}", ts), () -> log.info("determineNewTransactionStatus:: irrelevant request status change")); - return Optional.empty(); + return newTransactionStatus; + } + + private void updateTransactionStatuses(KafkaEvent event, EcsTlrEntity ecsTlr) { + determineNewTransactionStatus(event) + .ifPresent(newStatus -> updateTransactionStatuses(newStatus, ecsTlr)); + } + + private void updateTransactionStatuses(TransactionStatus.StatusEnum newStatus, EcsTlrEntity ecsTlr) { + log.info("updateTransactionStatuses:: updating primary transaction status to {}", newStatus::getValue); + updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newStatus, + ecsTlr.getPrimaryRequestTenantId()); + + log.info("updateTransactionStatuses:: updating intermediate transaction status to {}", newStatus::getValue); + updateTransactionStatus(ecsTlr.getIntermediateRequestDcbTransactionId(), newStatus, + ecsTlr.getIntermediateRequestTenantId()); + + log.info("updateTransactionStatuses:: updating secondary transaction status to {}", newStatus::getValue); + updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newStatus, + ecsTlr.getSecondaryRequestTenantId()); } private void updateTransactionStatus(UUID transactionId, TransactionStatus.StatusEnum newTransactionStatus, String tenant) { + if (transactionId == null) { + log.info("updateTransactionStatus:: transaction ID is null, doing nothing"); + return; + } + if (tenant == null) { + log.info("updateTransactionStatus:: tenant ID is null, doing nothing"); + return; + } + try { var currentStatus = dcbService.getTransactionStatus(transactionId, tenant).getStatus(); log.info("updateTransactionStatus:: current transaction status: {}", currentStatus); diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index bd93a4bf..713e6723 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -186,8 +186,8 @@ public CirculationItem createCirculationItem(String itemId, String instanceId, CirculationItem existingCirculationItem = executionService.executeSystemUserScoped( circulationItemTenantId, () -> circulationItemClient.getCirculationItem(itemId)); if (existingCirculationItem != null) { - log.info("createCirculationItem:: circulation item already exists in ten" + - "ant {}", circulationItemTenantId); + log.info("createCirculationItem:: circulation item already exists in tenant {}", + circulationItemTenantId); return existingCirculationItem; } From bc91bc6ca0acf730dc6960437f4e91d5f94a393f Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Thu, 5 Dec 2024 14:59:04 +0200 Subject: [PATCH 22/30] MODTLR-98 Refactoring --- .../org/folio/service/RequestService.java | 13 +- .../folio/service/impl/EcsTlrServiceImpl.java | 40 +---- .../service/impl/RequestServiceImpl.java | 160 +++++++++--------- .../org/folio/service/EcsTlrServiceTest.java | 2 +- 4 files changed, 89 insertions(+), 126 deletions(-) diff --git a/src/main/java/org/folio/service/RequestService.java b/src/main/java/org/folio/service/RequestService.java index b04bf10d..32ddba45 100644 --- a/src/main/java/org/folio/service/RequestService.java +++ b/src/main/java/org/folio/service/RequestService.java @@ -12,18 +12,15 @@ import org.folio.support.CqlQuery; public interface RequestService { - RequestWrapper createPrimaryRequest(Request request, String primaryRequestTenantId); + RequestWrapper createPrimaryRequest(Request request, String primaryRequestTenantId, + String secondaryRequestTenantId); RequestWrapper createSecondaryRequest(Request request, String primaryRequestTenantId, Collection secondaryRequestTenantIds); - RequestWrapper createIntermediateRequest(Request request, String primaryRequestTenantId, String intermediateRequestTenantId); - -// CirculationItem createCirculationItem(String itemId, String instanceId, -// String circulationItemTenantId, String inventoryTenantId); - - CirculationItem createCirculationItem(String itemId, String instanceId, - String pickupLocation, String circulationItemTenantId, String inventoryTenantId); + RequestWrapper createIntermediateRequest(Request intermediateRequest, + String primaryRequestTenantId, String intermediateRequestTenantId, + String secondaryRequestTenantId); CirculationItem updateCirculationItemOnRequestCreation(CirculationItem circulationItem, Request secondaryRequest); diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 1d41a87a..ae7f03dd 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -63,49 +63,19 @@ public EcsTlr create(EcsTlr ecsTlrDto) { Request secondaryRequest = secondaryRequestWrapper.request(); String secondaryRequestTenantId = secondaryRequestWrapper.tenantId(); - log.info("create:: Creating circulation item for ECS TLR (ILR) in the primary request tenant {}, instance {}, item {}, requester {}", - primaryRequestTenantId, ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); - CirculationItem circulationItem = requestService.createCirculationItem( - secondaryRequest.getItemId(), secondaryRequest.getInstanceId(), - secondaryRequest.getPickupServicePointId(), primaryRequestTenantId, - secondaryRequestTenantId); - log.info("create:: Creating primary request for ECS TLR (ILR), instance {}, item {}, requester {}", ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); - RequestWrapper primaryRequest = requestService.createPrimaryRequest( - buildPrimaryRequest(secondaryRequest), primaryRequestTenantId); - - log.info("create:: Updating circulation item for ECS TLR (ILR), instance {}, item {}, requester {}", - ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); - requestService.updateCirculationItemOnRequestCreation(circulationItem, - secondaryRequest); + RequestWrapper primaryRequestWrapper = requestService.createPrimaryRequest( + buildPrimaryRequest(secondaryRequest), primaryRequestTenantId, secondaryRequestTenantId); - updateEcsTlr(ecsTlr, primaryRequest, secondaryRequestWrapper); + updateEcsTlr(ecsTlr, primaryRequestWrapper, secondaryRequestWrapper); var centralTenantId = userTenantsService.getCentralTenantId(); if (!primaryRequestTenantId.equals(centralTenantId)) { log.info("create:: Primary request tenant is not central, creating intermediate request"); - - log.info("create:: Creating circulation item for ECS TLR (ILR) in the central tenant {}, instance {}, item {}, requester {}", - centralTenantId, ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); - CirculationItem centralTenantCirculationItem = requestService.createCirculationItem( - secondaryRequest.getItemId(), secondaryRequest.getInstanceId(), - secondaryRequest.getPickupServicePointId(), centralTenantId, - secondaryRequestTenantId); - - log.info("create:: Creating intermediate request for ECS TLR (ILR), instance {}, item {}, requester {}", - ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId()); RequestWrapper intermediateRequest = requestService.createIntermediateRequest( - buildIntermediateRequest(secondaryRequest), primaryRequestTenantId, centralTenantId); - - log.info("create:: Intermediate request {} created, updating circulation item", - of(intermediateRequest) - .map(RequestWrapper::request) - .map(Request::getId) - .orElse(null)); - requestService.updateCirculationItemOnRequestCreation(centralTenantCirculationItem, - secondaryRequest); - + buildIntermediateRequest(secondaryRequest), primaryRequestTenantId, centralTenantId, + secondaryRequestTenantId); updateEcsTlrWithIntermediateRequest(ecsTlr, intermediateRequest); } diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index 713e6723..e3854720 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.UUID; import org.folio.client.feign.CirculationClient; @@ -60,17 +61,22 @@ public class RequestServiceImpl implements RequestService { public static final String HOLDINGS_RECORD_ID = "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9"; @Override - public RequestWrapper createPrimaryRequest(Request request, String primaryRequestTenantId) { - final String requestId = request.getId(); - log.info("createPrimaryRequest:: creating primary request {} in tenant ({})", - requestId, primaryRequestTenantId); - Request primaryRequest = executionService.executeSystemUserScoped(primaryRequestTenantId, - () -> circulationClient.createRequest(request)); - log.info("createPrimaryRequest:: primary request {} created in tenant ({})", - requestId, primaryRequestTenantId); - log.debug("createPrimaryRequest:: primary request: {}", () -> primaryRequest); - - return new RequestWrapper(primaryRequest, primaryRequestTenantId); + public RequestWrapper createPrimaryRequest(Request primaryRequest, + String primaryRequestTenantId, String secondaryRequestTenantId) { + + final String requestId = primaryRequest.getId(); + log.info("createPrimaryRequest:: creating primary request {} in tenant {}", requestId, + primaryRequestTenantId); + + return executionService.executeSystemUserScoped(primaryRequestTenantId, () -> { + CirculationItem circItem = createCirculationItem(primaryRequest, secondaryRequestTenantId); + Request request = circulationClient.createRequest(primaryRequest); + log.info("createPrimaryRequest:: primary request {} created in tenant {}", + requestId, primaryRequestTenantId); + log.debug("createPrimaryRequest:: primary request: {}", () -> request); + updateCirculationItemOnRequestCreation(circItem, request); + return new RequestWrapper(request, primaryRequestTenantId); + }); } @Override @@ -92,25 +98,25 @@ public RequestWrapper createSecondaryRequest(Request request, String primaryRequ for (String secondaryRequestTenantId : secondaryRequestTenantIds) { try { return executionService.executeSystemUserScoped(secondaryRequestTenantId, () -> { - log.info("createSecondaryRequest:: creating requester {} in tenant ({})", + log.info("createSecondaryRequest:: creating requester {} in tenant {}", requesterId, secondaryRequestTenantId); cloneRequester(primaryRequestRequester); - log.info("createSecondaryRequest:: creating pickup service point {} in tenant ({})", + log.info("createSecondaryRequest:: creating pickup service point {} in tenant {}", pickupServicePointId, secondaryRequestTenantId); servicePointCloningService.clone(primaryRequestPickupServicePoint); - log.info("createSecondaryRequest:: creating secondary request {} in tenant ({})", + log.info("createSecondaryRequest:: creating secondary request {} in tenant {}", requestId, secondaryRequestTenantId); Request secondaryRequest = circulationClient.createRequest(request); - log.info("createSecondaryRequest:: secondary request {} created in tenant ({})", + log.info("createSecondaryRequest:: secondary request {} created in tenant {}", secondaryRequest.getId(), secondaryRequestTenantId); log.debug("createSecondaryRequest:: secondary request: {}", () -> secondaryRequest); return new RequestWrapper(secondaryRequest, secondaryRequestTenantId); }); } catch (Exception e) { - log.error("createSecondaryRequest:: failed to create secondary request in tenant ({}): {}", + log.error("createSecondaryRequest:: failed to create secondary request in tenant {}: {}", secondaryRequestTenantId, e.getMessage()); log.debug("createSecondaryRequest:: ", e); } @@ -124,38 +130,44 @@ public RequestWrapper createSecondaryRequest(Request request, String primaryRequ } @Override - public RequestWrapper createIntermediateRequest(Request request, String primaryRequestTenantId, String intermediateRequestTenantId) { - log.info("createIntermediateRequest:: creating intermediate request in tenant {}, instance {}, item {}, requester {}", - intermediateRequestTenantId, request.getInstanceId(), request.getItemId(), request.getRequesterId()); + public RequestWrapper createIntermediateRequest(Request intermediateRequest, + String primaryRequestTenantId, String intermediateRequestTenantId, + String secondaryRequestTenantId) { + + log.info("createIntermediateRequest:: creating intermediate request in tenant {}, instance {}," + + " item {}, requester {}", intermediateRequestTenantId, intermediateRequest.getInstanceId(), + intermediateRequest.getItemId(), intermediateRequest.getRequesterId()); -// Request intermediateRequest = executionService.executeSystemUserScoped(intermediateRequestTenantId, -// () -> circulationClient.createRequest(request)); try { - return executionService.executeSystemUserScoped(intermediateRequestTenantId, () -> { - final String requesterId = request.getRequesterId(); - final String pickupServicePointId = request.getPickupServicePointId(); - - User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId, - () -> userService.find(requesterId)); - ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped( - primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId)); - - log.info("createIntermediateRequest:: creating requester {} in tenant ({})", - requesterId, intermediateRequestTenantId); - cloneRequester(primaryRequestRequester); - - log.info("createIntermediateRequest:: creating pickup service point {} in tenant ({})", - pickupServicePointId, intermediateRequestTenantId); - servicePointCloningService.clone(primaryRequestPickupServicePoint); - - log.info("createIntermediateRequest:: creating intermediate request in tenant {}", - intermediateRequestTenantId); - Request intermediateRequest = circulationClient.createRequest(request); - log.info("createIntermediateRequest:: intermediate request created in tenant ({})", intermediateRequestTenantId); - log.info("createIntermediateRequest:: intermediate request: {}", () -> intermediateRequest); - - return new RequestWrapper(intermediateRequest, intermediateRequestTenantId); - }); + final String requesterId = intermediateRequest.getRequesterId(); + final String pickupServicePointId = intermediateRequest.getPickupServicePointId(); + + // TODO: fetch both in one call to system user + User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId, + () -> userService.find(requesterId)); + ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped( + primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId)); + + log.info("createIntermediateRequest:: creating requester {} in tenant {}", + requesterId, intermediateRequestTenantId); + cloneRequester(primaryRequestRequester); + + log.info("createIntermediateRequest:: creating pickup service point {} in tenant {}", + pickupServicePointId, intermediateRequestTenantId); + servicePointCloningService.clone(primaryRequestPickupServicePoint); + + CirculationItem circItem = createCirculationItem(intermediateRequest, secondaryRequestTenantId); + + log.info("createIntermediateRequest:: creating intermediate request in tenant {}", + intermediateRequestTenantId); + Request request = circulationClient.createRequest(intermediateRequest); + log.info("createIntermediateRequest:: intermediate request {} created in tenant {}", + request.getId(), intermediateRequestTenantId); + log.info("createIntermediateRequest:: intermediate request: {}", () -> request); + + updateCirculationItemOnRequestCreation(circItem, request); + + return new RequestWrapper(request, intermediateRequestTenantId); } catch (Exception e) { log.error("createIntermediateRequest:: failed to create intermediate request in tenant {}: {}", intermediateRequestTenantId, e.getMessage()); @@ -164,18 +176,18 @@ public RequestWrapper createIntermediateRequest(Request request, String primaryR String errorMessage = format( "Failed to create intermediate request for instance %s, item %s, requester %s in tenant %s", - request.getInstanceId(), request.getItemId(), request.getRequesterId(), intermediateRequestTenantId); + intermediateRequest.getInstanceId(), intermediateRequest.getItemId(), intermediateRequest.getRequesterId(), intermediateRequestTenantId); log.error("createIntermediateRequest:: {}", errorMessage); throw new RequestCreatingException(errorMessage); } - @Override - public CirculationItem createCirculationItem(String itemId, String instanceId, - String pickupLocation, String circulationItemTenantId, String inventoryTenantId) { + private CirculationItem createCirculationItem(Request request, String inventoryTenantId) { + String itemId = request.getItemId(); + String instanceId = request.getInstanceId(); + String pickupLocation = request.getPickupServicePointId(); - log.info("createCirculationItem:: Creating circulation item, params: itemId={}, " + - "instanceId={}, pickupLocation={}, circulationItemTenantId={}, inventoryTenantId={}", - itemId, instanceId, pickupLocation, circulationItemTenantId, inventoryTenantId); + log.info("createCirculationItem:: creating circulation item, params: itemId={}, instanceId={}, " + + "pickupLocation={}, inventoryTenantId={}", itemId, instanceId, pickupLocation, inventoryTenantId); if (itemId == null || instanceId == null) { log.info("createCirculationItem:: item ID is {}, instance ID is {}, skipping", itemId, instanceId); @@ -183,15 +195,17 @@ public CirculationItem createCirculationItem(String itemId, String instanceId, } // Check if circulation item already exists in the tenant we want to create it in - CirculationItem existingCirculationItem = executionService.executeSystemUserScoped( - circulationItemTenantId, () -> circulationItemClient.getCirculationItem(itemId)); + CirculationItem existingCirculationItem = circulationItemClient.getCirculationItem(itemId); if (existingCirculationItem != null) { - log.info("createCirculationItem:: circulation item already exists in tenant {}", - circulationItemTenantId); - + log.info("createCirculationItem:: circulation item already exists in status '{}'", + Optional.ofNullable(existingCirculationItem.getStatus()) + .map(CirculationItemStatus::getName) + .map(CirculationItemStatus.NameEnum::getValue) + .orElse(null)); return existingCirculationItem; } + // TODO: fetch both in one system user call InventoryItem item = getItemFromStorage(itemId, inventoryTenantId); InventoryInstance instance = getInstanceFromStorage(instanceId, inventoryTenantId); @@ -217,42 +231,24 @@ public CirculationItem createCirculationItem(String itemId, String instanceId, .effectiveLocationId(item.getEffectiveLocationId()) .lendingLibraryCode("TEST_CODE"); - var centralTenantId = userTenantsService.getCentralTenantId(); - - log.info("createCirculationItem:: Creating circulation item {} in tenant {}", - circulationItem.toString(), circulationItemTenantId); - return systemUserScopedExecutionService.executeSystemUserScoped( - circulationItemTenantId, () -> circulationItemClient.createCirculationItem(itemId, circulationItem)); - -// if (circulationItemTenantId.equals(centralTenantId)) { -// log.info("createCirculationItem:: Creating circulation item {} locally in Central", -// circulationItem.toString()); -// return circulationItemClient.createCirculationItem(itemId, circulationItem); -// } else { -// log.info("createCirculationItem:: Creating circulation item {} in tenant {}", -// circulationItem.toString(), circulationItemTenantId); -// return systemUserScopedExecutionService.executeSystemUserScoped( -// circulationItemTenantId, () -> circulationItemClient.createCirculationItem(itemId, circulationItem)); -// } + log.info("createCirculationItem:: creating circulation item {}", circulationItem.toString()); + return circulationItemClient.createCirculationItem(itemId, circulationItem); } @Override public CirculationItem updateCirculationItemOnRequestCreation(CirculationItem circulationItem, - Request secondaryRequest) { + Request request) { if (circulationItem == null) { log.info("updateCirculationItemOnRequestCreation:: circulation item is null, skipping"); return null; } - log.info("updateCirculationItemOnRequestCreation:: updating circulation item {}", circulationItem.getId()); - if (secondaryRequest.getRequestType() == Request.RequestTypeEnum.PAGE) { - log.info("updateCirculationItemOnRequestCreation:: secondary request {} type is " + - "Page, updating circulation item {} with status Paged", secondaryRequest.getId(), - circulationItem.getId()); - + if (request.getRequestType() == Request.RequestTypeEnum.PAGE) { + log.info("updateCirculationItemOnRequestCreation:: request {} type is 'Page', " + + "updating circulation item {} with status 'Paged'", request.getId(), circulationItem.getId()); circulationItem.getStatus().setName(CirculationItemStatus.NameEnum.PAGED); circulationItemClient.updateCirculationItem(circulationItem.getId().toString(), circulationItem); diff --git a/src/test/java/org/folio/service/EcsTlrServiceTest.java b/src/test/java/org/folio/service/EcsTlrServiceTest.java index 68139a00..b741d028 100644 --- a/src/test/java/org/folio/service/EcsTlrServiceTest.java +++ b/src/test/java/org/folio/service/EcsTlrServiceTest.java @@ -104,7 +104,7 @@ void ecsTlrShouldBeCreatedThenUpdatedAndDeleted(EcsTlr.RequestLevelEnum requestL .thenReturn(borrowingTenant); when(tenantService.getSecondaryRequestTenants(any(EcsTlrEntity.class))) .thenReturn(List.of(lendingTenant)); - when(requestService.createPrimaryRequest(any(Request.class), any(String.class))) + when(requestService.createPrimaryRequest(any(Request.class), any(String.class), any(String.class))) .thenReturn(new RequestWrapper(primaryRequest, borrowingTenant)); when(requestService.createSecondaryRequest(any(Request.class), any(String.class), any())) .thenReturn(new RequestWrapper(secondaryRequest, borrowingTenant)); From 6364fc4675b652a3f9f028d9c4693dd56a74f3d3 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Thu, 5 Dec 2024 17:23:14 +0200 Subject: [PATCH 23/30] MODTLR-98 Ignore transaction status update errors --- .../folio/service/impl/RequestEventHandler.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java index fbc5b43b..f8087ace 100644 --- a/src/main/java/org/folio/service/impl/RequestEventHandler.java +++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java @@ -189,27 +189,32 @@ private void updateTransactionStatuses(TransactionStatus.StatusEnum newStatus, E } private void updateTransactionStatus(UUID transactionId, - TransactionStatus.StatusEnum newTransactionStatus, String tenant) { + TransactionStatus.StatusEnum newStatus, String tenantId) { if (transactionId == null) { log.info("updateTransactionStatus:: transaction ID is null, doing nothing"); return; } - if (tenant == null) { + if (tenantId == null) { log.info("updateTransactionStatus:: tenant ID is null, doing nothing"); return; } try { - var currentStatus = dcbService.getTransactionStatus(transactionId, tenant).getStatus(); + var currentStatus = dcbService.getTransactionStatus(transactionId, tenantId).getStatus(); log.info("updateTransactionStatus:: current transaction status: {}", currentStatus); - if (newTransactionStatus.getValue().equals(currentStatus.getValue())) { + if (newStatus.getValue().equals(currentStatus.getValue())) { log.info("updateTransactionStatus:: transaction status did not change, doing nothing"); return; } - dcbService.updateTransactionStatus(transactionId, newTransactionStatus, tenant); + log.info("updateTransactionStatus: changing status of transaction {} in tenant {} from {} to {}", + transactionId, tenantId, currentStatus.getValue(), newStatus.getValue()); + dcbService.updateTransactionStatus(transactionId, newStatus, tenantId); } catch (FeignException.NotFound e) { log.error("updateTransactionStatus:: transaction {} not found: {}", transactionId, e.getMessage()); + } catch (Exception e) { + log.error("updateTransactionStatus:: failed to update transaction status: {}", e::getMessage); + log.debug("updateTransactionStatus:: ", e); } } From 2c930aa3f8aa6b5928e19f299195b55bfa28cf2d Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 6 Dec 2024 13:55:47 +0200 Subject: [PATCH 24/30] MODTLR-98 Add support for loan events --- descriptors/ModuleDescriptor-template.json | 23 +- .../listener/kafka/KafkaEventListener.java | 29 +- .../impl/AllowedServicePointsServiceImpl.java | 2 - .../folio/service/impl/LoanEventHandler.java | 281 ++++++++++++++++++ .../service/impl/RequestServiceImpl.java | 1 - .../folio/service/impl/TenantServiceImpl.java | 3 - src/main/resources/swagger.api/ecs-tlr.yaml | 2 + .../resources/swagger.api/schemas/loan.json | 166 +++++++++++ .../listener/KafkaEventListenerTest.java | 7 +- 9 files changed, 500 insertions(+), 14 deletions(-) create mode 100644 src/main/java/org/folio/service/impl/LoanEventHandler.java create mode 100644 src/main/resources/swagger.api/schemas/loan.json diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index 4da59f87..8072b311 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -124,7 +124,28 @@ "permissionsRequired": ["tlr.pick-slips.collection.get"], "modulePermissions": [ "user-tenants.collection.get", - "search.instances.collection.get", + "circulation-storage.requests.item.get", + "circulation-storage.requests.collection.get", + "users.item.get", + "users.collection.get", + "usergroups.item.get", + "usergroups.collection.get", + "departments.item.get", + "departments.collection.get", + "addresstypes.item.get", + "addresstypes.collection.get", + "inventory-storage.service-points.item.get", + "inventory-storage.service-points.collection.get", + "inventory-storage.instances.item.get", + "inventory-storage.instances.collection.get" + ] + }, + { + "methods": ["GET"], + "pathPattern": "/tlr/staff-slips/search-slips/{servicePointId}", + "permissionsRequired": ["tlr.search-slips.collection.get"], + "modulePermissions": [ + "user-tenants.collection.get", "circulation-storage.requests.item.get", "circulation-storage.requests.collection.get", "users.item.get", diff --git a/src/main/java/org/folio/listener/kafka/KafkaEventListener.java b/src/main/java/org/folio/listener/kafka/KafkaEventListener.java index f6e7b840..dc0f9a05 100644 --- a/src/main/java/org/folio/listener/kafka/KafkaEventListener.java +++ b/src/main/java/org/folio/listener/kafka/KafkaEventListener.java @@ -5,12 +5,14 @@ import java.nio.charset.StandardCharsets; import java.util.Optional; +import org.folio.domain.dto.Loan; import org.folio.domain.dto.Request; import org.folio.domain.dto.RequestsBatchUpdate; import org.folio.domain.dto.User; import org.folio.domain.dto.UserGroup; import org.folio.exception.KafkaEventDeserializationException; import org.folio.service.KafkaEventHandler; +import org.folio.service.impl.LoanEventHandler; import org.folio.service.impl.RequestBatchUpdateEventHandler; import org.folio.service.impl.RequestEventHandler; import org.folio.service.impl.UserEventHandler; @@ -34,18 +36,22 @@ public class KafkaEventListener { private static final ObjectMapper objectMapper = new ObjectMapper(); private final RequestEventHandler requestEventHandler; + private final LoanEventHandler loanEventHandler; private final UserGroupEventHandler userGroupEventHandler; private final UserEventHandler userEventHandler; private final SystemUserScopedExecutionService systemUserScopedExecutionService; private final RequestBatchUpdateEventHandler requestBatchEventHandler; - public KafkaEventListener(@Autowired RequestEventHandler requestEventHandler, - @Autowired RequestBatchUpdateEventHandler requestBatchEventHandler, - @Autowired SystemUserScopedExecutionService systemUserScopedExecutionService, - @Autowired UserGroupEventHandler userGroupEventHandler, - @Autowired UserEventHandler userEventHandler) { + @Autowired + public KafkaEventListener(RequestEventHandler requestEventHandler, + LoanEventHandler loanEventHandler, + RequestBatchUpdateEventHandler requestBatchEventHandler, + SystemUserScopedExecutionService systemUserScopedExecutionService, + UserGroupEventHandler userGroupEventHandler, + UserEventHandler userEventHandler) { this.requestEventHandler = requestEventHandler; + this.loanEventHandler = loanEventHandler; this.systemUserScopedExecutionService = systemUserScopedExecutionService; this.userGroupEventHandler = userGroupEventHandler; this.requestBatchEventHandler = requestBatchEventHandler; @@ -76,6 +82,19 @@ public void handleRequestBatchUpdateEvent(String eventString, MessageHeaders mes log.info("handleRequestBatchUpdateEvent:: event consumed: {}", event::getId); } + @KafkaListener( + topicPattern = "${folio.environment}\\.\\w+\\.circulation\\.loan", + groupId = "${spring.kafka.consumer.group-id}" + ) + public void handleLoanEvent(String eventString, MessageHeaders messageHeaders) { + log.debug("handleLoanEvent:: event: {}", () -> eventString); + KafkaEvent event = deserialize(eventString, messageHeaders, Loan.class); + log.info("handleLoanEvent:: event received: {}", event::getId); + log.info("handleLoanEvent:: event: {}", eventString); + handleEvent(event, loanEventHandler); + log.info("handleLoanEvent:: event consumed: {}", event::getId); + } + private void handleEvent(KafkaEvent event, KafkaEventHandler handler) { try { systemUserScopedExecutionService.executeAsyncSystemUserScoped(CENTRAL_TENANT_ID, diff --git a/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java b/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java index 8ff2866f..f93cc6f9 100644 --- a/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java +++ b/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java @@ -62,8 +62,6 @@ private AllowedServicePointsResponse getForCreate(AllowedServicePointsRequest re Map recall = new HashMap<>(); for (String tenantId : getLendingTenants(request)) { var servicePoints = getAllowedServicePointsFromTenant(request, patronGroupId, tenantId); - log.info("getForCreate:: service points from {}: {}", tenantId, servicePoints); - combineAndFilterDuplicates(page, servicePoints.getPage()); combineAndFilterDuplicates(hold, servicePoints.getHold()); combineAndFilterDuplicates(recall, servicePoints.getRecall()); diff --git a/src/main/java/org/folio/service/impl/LoanEventHandler.java b/src/main/java/org/folio/service/impl/LoanEventHandler.java new file mode 100644 index 00000000..862aef39 --- /dev/null +++ b/src/main/java/org/folio/service/impl/LoanEventHandler.java @@ -0,0 +1,281 @@ +package org.folio.service.impl; + +import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.PRIMARY; +import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.SECONDARY; +import static org.folio.domain.dto.TransactionStatus.StatusEnum.AWAITING_PICKUP; +import static org.folio.domain.dto.TransactionStatus.StatusEnum.CANCELLED; +import static org.folio.domain.dto.TransactionStatus.StatusEnum.ITEM_CHECKED_OUT; +import static org.folio.domain.dto.TransactionStatus.StatusEnum.OPEN; +import static org.folio.support.KafkaEvent.EventType.UPDATED; + +import java.util.Date; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Function; + +import org.folio.domain.dto.Loan; +import org.folio.domain.dto.Request; +import org.folio.domain.dto.Request.EcsRequestPhaseEnum; +import org.folio.domain.dto.Request.FulfillmentPreferenceEnum; +import org.folio.domain.dto.ServicePoint; +import org.folio.domain.dto.TransactionStatus; +import org.folio.domain.entity.EcsTlrEntity; +import org.folio.repository.EcsTlrRepository; +import org.folio.service.CloningService; +import org.folio.service.DcbService; +import org.folio.service.KafkaEventHandler; +import org.folio.service.RequestService; +import org.folio.service.ServicePointService; +import org.folio.spring.service.SystemUserScopedExecutionService; +import org.folio.support.KafkaEvent; +import org.springframework.stereotype.Service; + +import feign.FeignException; +import lombok.AllArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@AllArgsConstructor +@Service +@Log4j2 +public class LoanEventHandler implements KafkaEventHandler { + + private final DcbService dcbService; + private final EcsTlrRepository ecsTlrRepository; + private final SystemUserScopedExecutionService executionService; + private final ServicePointService servicePointService; + private final CloningService servicePointCloningService; + private final RequestService requestService; + + @Override + public void handle(KafkaEvent event) { + log.info("handle:: processing loan event: {}", event::getId); + if (event.getType() == UPDATED) { + handleLoanUpdateEvent(event); + } else { + log.info("handle:: ignoring event {} of unsupported type: {}", event::getId, event::getType); + } + log.info("handle:: loan event processed: {}", event::getId); + } + + private void handleLoanUpdateEvent(KafkaEvent event) { + log.info("handleLoanUpdateEvent:: handling loan update event: {}", event::getId); +// Loan updatedRequest = event.getData().getNewVersion(); +// if (updatedRequest == null) { +// log.warn("handleRequestUpdateEvent:: event does not contain new version of request"); +// return; +// } +// if (updatedRequest.getEcsRequestPhase() == null) { +// log.info("handleRequestUpdateEvent:: updated request is not an ECS request"); +// return; +// } +// if (updatedRequest.getEcsRequestPhase() == SECONDARY && updatedRequest.getItemId() == null) { +// log.info("handleRequestUpdateEvent:: updated secondary request does not contain itemId"); +// return; +// } +// String requestId = updatedRequest.getId(); +// log.info("handleRequestUpdateEvent:: looking for ECS TLR for request {}", requestId); +// // we can search by either primary or secondary request ID, they are identical +// ecsTlrRepository.findBySecondaryRequestId(UUID.fromString(requestId)).ifPresentOrElse( +// ecsTlr -> handleRequestUpdateEvent(ecsTlr, event), +// () -> log.info("handleSecondaryRequestUpdate: ECS TLR for request {} not found", requestId)); + } + + private void handleRequestUpdateEvent(EcsTlrEntity ecsTlr, KafkaEvent event) { + log.debug("handleRequestUpdateEvent:: ecsTlr={}", () -> ecsTlr); + Request updatedRequest = event.getData().getNewVersion(); + + if (!requestMatchesEcsTlr(ecsTlr, updatedRequest, event.getTenantIdHeaderValue())) { + return; + } + if (updatedRequest.getEcsRequestPhase() == PRIMARY) { + handlePrimaryRequestUpdate(ecsTlr, event); + } + if (updatedRequest.getEcsRequestPhase() == SECONDARY) { + handleSecondaryRequestUpdate(ecsTlr, event); + } + } + + private static boolean requestMatchesEcsTlr(EcsTlrEntity ecsTlr, Request updatedRequest, + String updatedRequestTenant) { + + final EcsRequestPhaseEnum updatedRequestPhase = updatedRequest.getEcsRequestPhase(); + final UUID updatedRequestId = UUID.fromString(updatedRequest.getId()); + + if (updatedRequestPhase == PRIMARY && updatedRequestId.equals(ecsTlr.getPrimaryRequestId()) + && updatedRequestTenant.equals(ecsTlr.getPrimaryRequestTenantId())) { + log.info("requestMatchesEcsTlr:: updated primary request matches ECS TLR"); + return true; + } else if (updatedRequestPhase == SECONDARY && updatedRequestId.equals(ecsTlr.getSecondaryRequestId()) + && updatedRequestTenant.equals(ecsTlr.getSecondaryRequestTenantId())) { + log.info("requestMatchesEcsTlr:: updated secondary request matches ECS TLR"); + return true; + } + log.warn("requestMatchesEcsTlr:: request does not match ECS TLR: updatedRequestPhase={}, " + + "updatedRequestId={}, updatedRequestTenant={}, ecsTlr={}", updatedRequestPhase, + updatedRequestId, updatedRequestTenant, ecsTlr); + return false; + } + + private void handlePrimaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) { + propagateChangesFromPrimaryToSecondaryRequest(ecsTlr, event); + updateTransactionStatuses(event, ecsTlr); + } + + private void handleSecondaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) { + processItemIdUpdate(ecsTlr, event.getData().getNewVersion()); + updateTransactionStatuses(event, ecsTlr); + } + + private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) { + if (ecsTlr.getItemId() != null) { + log.info("processItemIdUpdate:: ECS TLR {} already has itemId {}", ecsTlr::getId, ecsTlr::getItemId); + return; + } + log.info("processItemIdUpdate:: updating ECS TLR {} with itemId {}", ecsTlr::getId, + updatedRequest::getItemId); + ecsTlr.setItemId(UUID.fromString(updatedRequest.getItemId())); + // TODO: change this if Page request works + dcbService.createTransactions(ecsTlr, updatedRequest); + ecsTlrRepository.save(ecsTlr); + log.info("processItemIdUpdate: ECS TLR {} is updated", ecsTlr::getId); + } + + private static Optional determineNewTransactionStatus( + KafkaEvent event) { + + final Request.StatusEnum oldRequestStatus = event.getData().getOldVersion().getStatus(); + final Request.StatusEnum newRequestStatus = event.getData().getNewVersion().getStatus(); + log.info("determineNewTransactionStatus:: oldRequestStatus='{}', newRequestStatus='{}'", + oldRequestStatus, newRequestStatus); + + if (newRequestStatus == oldRequestStatus) { + log.info("determineNewTransactionStatus:: request status did not change"); + return Optional.empty(); + } + + var newTransactionStatus = Optional.ofNullable( + switch (newRequestStatus) { + case OPEN_IN_TRANSIT -> OPEN; + case OPEN_AWAITING_PICKUP -> AWAITING_PICKUP; + case CLOSED_FILLED -> ITEM_CHECKED_OUT; + case CLOSED_CANCELLED -> CANCELLED; + default -> null; + }); + + newTransactionStatus.ifPresentOrElse( + ts -> log.info("determineNewTransactionStatus:: new transaction status: {}", ts), + () -> log.info("determineNewTransactionStatus:: irrelevant request status change")); + + return newTransactionStatus; + } + + private void updateTransactionStatuses(KafkaEvent event, EcsTlrEntity ecsTlr) { + determineNewTransactionStatus(event) + .ifPresent(newStatus -> updateTransactionStatuses(newStatus, ecsTlr)); + } + + private void updateTransactionStatuses(TransactionStatus.StatusEnum newStatus, EcsTlrEntity ecsTlr) { + log.info("updateTransactionStatuses:: updating primary transaction status to {}", newStatus::getValue); + updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newStatus, + ecsTlr.getPrimaryRequestTenantId()); + + log.info("updateTransactionStatuses:: updating intermediate transaction status to {}", newStatus::getValue); + updateTransactionStatus(ecsTlr.getIntermediateRequestDcbTransactionId(), newStatus, + ecsTlr.getIntermediateRequestTenantId()); + + log.info("updateTransactionStatuses:: updating secondary transaction status to {}", newStatus::getValue); + updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newStatus, + ecsTlr.getSecondaryRequestTenantId()); + } + + private void updateTransactionStatus(UUID transactionId, + TransactionStatus.StatusEnum newStatus, String tenantId) { + + if (transactionId == null) { + log.info("updateTransactionStatus:: transaction ID is null, doing nothing"); + return; + } + if (tenantId == null) { + log.info("updateTransactionStatus:: tenant ID is null, doing nothing"); + return; + } + + try { + var currentStatus = dcbService.getTransactionStatus(transactionId, tenantId).getStatus(); + log.info("updateTransactionStatus:: current transaction status: {}", currentStatus); + if (newStatus.getValue().equals(currentStatus.getValue())) { + log.info("updateTransactionStatus:: transaction status did not change, doing nothing"); + return; + } + log.info("updateTransactionStatus: changing status of transaction {} in tenant {} from {} to {}", + transactionId, tenantId, currentStatus.getValue(), newStatus.getValue()); + dcbService.updateTransactionStatus(transactionId, newStatus, tenantId); + } catch (FeignException.NotFound e) { + log.error("updateTransactionStatus:: transaction {} not found: {}", transactionId, e.getMessage()); + } catch (Exception e) { + log.error("updateTransactionStatus:: failed to update transaction status: {}", e::getMessage); + log.debug("updateTransactionStatus:: ", e); + } + } + + private void propagateChangesFromPrimaryToSecondaryRequest(EcsTlrEntity ecsTlr, + KafkaEvent event) { + + String secondaryRequestId = ecsTlr.getSecondaryRequestId().toString(); + String secondaryRequestTenantId = ecsTlr.getSecondaryRequestTenantId(); + Request primaryRequest = event.getData().getNewVersion(); + Request secondaryRequest = requestService.getRequestFromStorage( + secondaryRequestId, secondaryRequestTenantId); + + boolean shouldUpdateSecondaryRequest = false; + if (valueIsNotEqual(primaryRequest, secondaryRequest, Request::getRequestExpirationDate)) { + Date requestExpirationDate = primaryRequest.getRequestExpirationDate(); + log.info("propagateChangesFromPrimaryToSecondaryRequest:: request expiration date changed: {}", + requestExpirationDate); + secondaryRequest.setRequestExpirationDate(requestExpirationDate); + shouldUpdateSecondaryRequest = true; + } + if (valueIsNotEqual(primaryRequest, secondaryRequest, Request::getFulfillmentPreference)) { + FulfillmentPreferenceEnum fulfillmentPreference = primaryRequest.getFulfillmentPreference(); + log.info("propagateChangesFromPrimaryToSecondaryRequest:: fulfillment preference changed: {}", + fulfillmentPreference); + secondaryRequest.setFulfillmentPreference(fulfillmentPreference); + shouldUpdateSecondaryRequest = true; + } + if (valueIsNotEqual(primaryRequest, secondaryRequest, Request::getPickupServicePointId)) { + String pickupServicePointId = primaryRequest.getPickupServicePointId(); + log.info("propagateChangesFromPrimaryToSecondaryRequest:: pickup service point ID changed: {}", + pickupServicePointId); + secondaryRequest.setPickupServicePointId(pickupServicePointId); + shouldUpdateSecondaryRequest = true; + clonePickupServicePoint(ecsTlr, pickupServicePointId); + } + + if (!shouldUpdateSecondaryRequest) { + log.info("propagateChangesFromPrimaryToSecondaryRequest:: no relevant changes detected"); + return; + } + + log.info("propagateChangesFromPrimaryToSecondaryRequest:: updating secondary request"); + requestService.updateRequestInStorage(secondaryRequest, secondaryRequestTenantId); + log.info("propagateChangesFromPrimaryToSecondaryRequest:: secondary request updated"); + } + + private void clonePickupServicePoint(EcsTlrEntity ecsTlr, String pickupServicePointId) { + if (pickupServicePointId == null) { + log.info("clonePickupServicePoint:: pickupServicePointId is null, doing nothing"); + return; + } + log.info("clonePickupServicePoint:: ensuring that service point {} exists in lending tenant", + pickupServicePointId); + ServicePoint pickupServicePoint = executionService.executeSystemUserScoped( + ecsTlr.getPrimaryRequestTenantId(), () -> servicePointService.find(pickupServicePointId)); + executionService.executeSystemUserScoped(ecsTlr.getSecondaryRequestTenantId(), + () -> servicePointCloningService.clone(pickupServicePoint)); + } + + private static boolean valueIsNotEqual(T o1, T o2, Function valueExtractor) { + return !Objects.equals(valueExtractor.apply(o1), valueExtractor.apply(o2)); + } +} diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index d43ec863..869bac9a 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -163,7 +163,6 @@ public RequestWrapper createIntermediateRequest(Request intermediateRequest, Request request = circulationClient.createRequest(intermediateRequest); log.info("createIntermediateRequest:: intermediate request {} created in tenant {}", request.getId(), intermediateRequestTenantId); - log.info("createIntermediateRequest:: intermediate request: {}", () -> request); updateCirculationItemOnRequestCreation(circItem, request); diff --git a/src/main/java/org/folio/service/impl/TenantServiceImpl.java b/src/main/java/org/folio/service/impl/TenantServiceImpl.java index 61639fac..e1e67ca3 100644 --- a/src/main/java/org/folio/service/impl/TenantServiceImpl.java +++ b/src/main/java/org/folio/service/impl/TenantServiceImpl.java @@ -55,9 +55,6 @@ public String getPrimaryRequestTenantId(EcsTlrEntity ecsTlr) { log.info("getPrimaryRequestTenantId:: returning primaryRequestTenantId"); return ecsTlr.getPrimaryRequestTenantId(); - -// log.info("getPrimaryRequestTenantId:: getting borrowing tenant"); -// return HttpUtils.getTenantFromToken(); } @Override diff --git a/src/main/resources/swagger.api/ecs-tlr.yaml b/src/main/resources/swagger.api/ecs-tlr.yaml index dd60c16e..b1d4460c 100644 --- a/src/main/resources/swagger.api/ecs-tlr.yaml +++ b/src/main/resources/swagger.api/ecs-tlr.yaml @@ -103,6 +103,8 @@ components: $ref: 'schemas/request.json' requests: $ref: 'schemas/requests.json' + loan: + $ref: 'schemas/loan.json' searchInstancesResponse: $ref: 'schemas/search/searchInstancesResponse.yaml' searchItemResponse: diff --git a/src/main/resources/swagger.api/schemas/loan.json b/src/main/resources/swagger.api/schemas/loan.json new file mode 100644 index 00000000..1ab9653f --- /dev/null +++ b/src/main/resources/swagger.api/schemas/loan.json @@ -0,0 +1,166 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "title": "Loan", + "description": "Links the item with the patron and applies certain conditions based on policies", + "properties": { + "id": { + "description": "Unique ID (generated UUID) of the loan", + "type": "string" + }, + "userId": { + "description": "ID of the patron the item was lent to. Required for open loans, not required for closed loans (for anonymization).", + "type": "string" + }, + "proxyUserId": { + "description": "ID of the user representing a proxy for the patron", + "type": "string", + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + }, + "itemId": { + "description": "ID of the item lent to the patron", + "type": "string" + }, + "itemEffectiveLocationIdAtCheckOut": { + "description": "The effective location, at the time of checkout, of the item loaned to the patron.", + "type": "string", + "$ref": "uuid.json" + }, + "status": { + "description": "Overall status of the loan", + "type": "object", + "properties": { + "name": { + "description": "Name of the status (currently can be any value, values commonly used are Open and Closed)", + "type": "string" + } + } + }, + "loanDate": { + "description": "Date time when the loan began (typically represented according to rfc3339 section-5.6. Has not had the date-time format validation applied as was not supported at point of introduction and would now be a breaking change)", + "type": "string" + }, + "dueDate": { + "description": "Date time when the item is due to be returned", + "type": "string", + "format": "date-time" + }, + "returnDate": { + "description": "Date time when the item is returned and the loan ends (typically represented according to rfc3339 section-5.6. Has not had the date-time format validation applied as was not supported at point of introduction and would now be a breaking change)", + "type": "string" + }, + "systemReturnDate" : { + "description": "Date time when the returned item is actually processed", + "type": "string", + "format": "date-time" + }, + "action": { + "description": "Last action performed on a loan (currently can be any value, values commonly used are checkedout and checkedin)", + "type": "string" + }, + "actionComment": { + "description": "Comment to last action performed on a loan", + "type": "string" + }, + "itemStatus": { + "description": "Last item status used in relation to this loan (currently can be any value, values commonly used are Checked out and Available)", + "type": "string" + }, + "renewalCount": { + "description": "Count of how many times a loan has been renewed (incremented by the client)", + "type": "integer" + }, + "loanPolicyId": { + "description": "ID of last policy used in relation to this loan", + "type": "string" + }, + "checkoutServicePointId": { + "description": "ID of the Service Point where the last checkout occured", + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", + "type": "string" + }, + "checkinServicePointId": { + "description": "ID of the Service Point where the last checkin occured", + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", + "type": "string" + }, + "patronGroupIdAtCheckout": { + "description": "Patron Group Id at checkout", + "type": "string" + }, + "dueDateChangedByRecall": { + "description": "Indicates whether or not this loan had its due date modified by a recall on the loaned item", + "type": "boolean" + }, + "isDcb": { + "description": "Indicates whether or not this loan is associated for DCB use case", + "type": "boolean" + }, + "declaredLostDate" : { + "description": "Date and time the item was declared lost during this loan", + "type": "string", + "format": "date-time" + }, + "claimedReturnedDate": { + "description": "Date and time the item was claimed returned for this loan", + "type": "string", + "format": "date-time" + }, + "overdueFinePolicyId": { + "description": "ID of overdue fines policy at the time the item is check-in or renewed", + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", + "type": "string" + }, + "lostItemPolicyId": { + "description": "ID of lost item policy which determines when the item ages to lost and the associated fees or the associated fees if the patron declares the item lost.", + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", + "type": "string" + }, + "metadata": { + "description": "Metadata about creation and changes to loan, provided by the server (client should not provide)", + "type": "object", + "$ref": "metadata.json" + }, + "agedToLostDelayedBilling": { + "description": "Aged to Lost Delayed Billing processing", + "type": "object", + "properties": { + "lostItemHasBeenBilled": { + "description": "Indicates if the aged to lost fee has been billed (for use where delayed billing is set up)", + "type": "boolean" + }, + "dateLostItemShouldBeBilled": { + "description": "Indicates when the aged to lost fee should be billed (for use where delayed billing is set up)", + "type": "string", + "format": "date-time" + }, + "agedToLostDate": { + "description": "Date and time the item was aged to lost for this loan", + "type": "string", + "format": "date-time" + } + } + }, + "reminders" : { + "description": "Information about reminders for overdue loan", + "type": "object", + "properties": { + "lastFeeBilled": { + "description": "Information about the most recent reminder fee billing", + "type": "object", + "properties": { + "number": { + "description": "Last reminder fee billed, sequence number", + "type": "integer" + }, + "date": { + "description": "Last reminder fee billed, date", + "type": "string", + "format": "date-time" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/test/java/org/folio/listener/KafkaEventListenerTest.java b/src/test/java/org/folio/listener/KafkaEventListenerTest.java index 759f8272..fe5f8f5d 100644 --- a/src/test/java/org/folio/listener/KafkaEventListenerTest.java +++ b/src/test/java/org/folio/listener/KafkaEventListenerTest.java @@ -8,6 +8,7 @@ import java.util.Map; import org.folio.listener.kafka.KafkaEventListener; +import org.folio.service.impl.LoanEventHandler; import org.folio.service.impl.RequestBatchUpdateEventHandler; import org.folio.service.impl.RequestEventHandler; import org.folio.service.impl.UserEventHandler; @@ -24,6 +25,8 @@ class KafkaEventListenerTest { @Mock RequestEventHandler requestEventHandler; @Mock + LoanEventHandler loanEventHandler; + @Mock RequestBatchUpdateEventHandler requestBatchEventHandler; @Mock SystemUserScopedExecutionService systemUserScopedExecutionService; @@ -37,8 +40,8 @@ void shouldHandleExceptionInEventHandler() { doThrow(new NullPointerException("NPE")).when(systemUserScopedExecutionService) .executeAsyncSystemUserScoped(any(), any()); KafkaEventListener kafkaEventListener = new KafkaEventListener(requestEventHandler, - requestBatchEventHandler, systemUserScopedExecutionService, userGroupEventHandler, - userEventHandler); + loanEventHandler, requestBatchEventHandler, systemUserScopedExecutionService, + userGroupEventHandler, userEventHandler); kafkaEventListener.handleRequestEvent("{}", new MessageHeaders(Map.of(TENANT, "default".getBytes()))); From 311c681a818f57a6f8d34eec4d437505835e0659 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 6 Dec 2024 17:28:56 +0200 Subject: [PATCH 25/30] MODTLR-98 Fix existing tests --- .../org/folio/service/RequestService.java | 2 - .../folio/service/impl/EcsTlrServiceImpl.java | 4 +- .../folio/service/impl/LoanEventHandler.java | 257 +----------------- .../service/impl/RequestServiceImpl.java | 3 - .../java/org/folio/api/EcsTlrApiTest.java | 2 +- .../controller/KafkaEventListenerTest.java | 2 +- .../org/folio/service/EcsTlrServiceTest.java | 7 +- 7 files changed, 17 insertions(+), 260 deletions(-) diff --git a/src/main/java/org/folio/service/RequestService.java b/src/main/java/org/folio/service/RequestService.java index 966c62e2..e9e86fe1 100644 --- a/src/main/java/org/folio/service/RequestService.java +++ b/src/main/java/org/folio/service/RequestService.java @@ -26,9 +26,7 @@ CirculationItem updateCirculationItemOnRequestCreation(CirculationItem circulati Request secondaryRequest); InventoryItem getItemFromStorage(String itemId, String tenantId); - InventoryInstance getInstanceFromStorage(String instanceId, String tenantId); - Request getRequestFromStorage(String requestId, String tenantId); Request getRequestFromStorage(String requestId); Collection getRequestsFromStorage(CqlQuery query, String idIndex, Collection ids); diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index ae7f03dd..589a13ea 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -9,7 +9,6 @@ import java.util.stream.Collectors; import org.folio.domain.RequestWrapper; -import org.folio.domain.dto.CirculationItem; import org.folio.domain.dto.EcsTlr; import org.folio.domain.dto.Request; import org.folio.domain.entity.EcsTlrEntity; @@ -20,6 +19,7 @@ import org.folio.service.EcsTlrService; import org.folio.service.RequestService; import org.folio.service.TenantService; +import org.folio.service.UserTenantsService; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -35,7 +35,7 @@ public class EcsTlrServiceImpl implements EcsTlrService { private final TenantService tenantService; private final RequestService requestService; private final DcbService dcbService; - private final UserTenantsServiceImpl userTenantsService; + private final UserTenantsService userTenantsService; @Override public Optional get(UUID id) { diff --git a/src/main/java/org/folio/service/impl/LoanEventHandler.java b/src/main/java/org/folio/service/impl/LoanEventHandler.java index 862aef39..dc2dc630 100644 --- a/src/main/java/org/folio/service/impl/LoanEventHandler.java +++ b/src/main/java/org/folio/service/impl/LoanEventHandler.java @@ -1,37 +1,13 @@ package org.folio.service.impl; -import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.PRIMARY; -import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.SECONDARY; -import static org.folio.domain.dto.TransactionStatus.StatusEnum.AWAITING_PICKUP; -import static org.folio.domain.dto.TransactionStatus.StatusEnum.CANCELLED; -import static org.folio.domain.dto.TransactionStatus.StatusEnum.ITEM_CHECKED_OUT; -import static org.folio.domain.dto.TransactionStatus.StatusEnum.OPEN; +import static org.folio.support.KafkaEvent.EventType.CREATED; import static org.folio.support.KafkaEvent.EventType.UPDATED; -import java.util.Date; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.function.Function; - import org.folio.domain.dto.Loan; -import org.folio.domain.dto.Request; -import org.folio.domain.dto.Request.EcsRequestPhaseEnum; -import org.folio.domain.dto.Request.FulfillmentPreferenceEnum; -import org.folio.domain.dto.ServicePoint; -import org.folio.domain.dto.TransactionStatus; -import org.folio.domain.entity.EcsTlrEntity; -import org.folio.repository.EcsTlrRepository; -import org.folio.service.CloningService; -import org.folio.service.DcbService; import org.folio.service.KafkaEventHandler; -import org.folio.service.RequestService; -import org.folio.service.ServicePointService; -import org.folio.spring.service.SystemUserScopedExecutionService; import org.folio.support.KafkaEvent; import org.springframework.stereotype.Service; -import feign.FeignException; import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -40,17 +16,12 @@ @Log4j2 public class LoanEventHandler implements KafkaEventHandler { - private final DcbService dcbService; - private final EcsTlrRepository ecsTlrRepository; - private final SystemUserScopedExecutionService executionService; - private final ServicePointService servicePointService; - private final CloningService servicePointCloningService; - private final RequestService requestService; - @Override public void handle(KafkaEvent event) { log.info("handle:: processing loan event: {}", event::getId); - if (event.getType() == UPDATED) { + if (event.getType() == CREATED) { + handleLoanCreationEvent(event); + } else if (event.getType() == UPDATED) { handleLoanUpdateEvent(event); } else { log.info("handle:: ignoring event {} of unsupported type: {}", event::getId, event::getType); @@ -58,224 +29,12 @@ public void handle(KafkaEvent event) { log.info("handle:: loan event processed: {}", event::getId); } - private void handleLoanUpdateEvent(KafkaEvent event) { - log.info("handleLoanUpdateEvent:: handling loan update event: {}", event::getId); -// Loan updatedRequest = event.getData().getNewVersion(); -// if (updatedRequest == null) { -// log.warn("handleRequestUpdateEvent:: event does not contain new version of request"); -// return; -// } -// if (updatedRequest.getEcsRequestPhase() == null) { -// log.info("handleRequestUpdateEvent:: updated request is not an ECS request"); -// return; -// } -// if (updatedRequest.getEcsRequestPhase() == SECONDARY && updatedRequest.getItemId() == null) { -// log.info("handleRequestUpdateEvent:: updated secondary request does not contain itemId"); -// return; -// } -// String requestId = updatedRequest.getId(); -// log.info("handleRequestUpdateEvent:: looking for ECS TLR for request {}", requestId); -// // we can search by either primary or secondary request ID, they are identical -// ecsTlrRepository.findBySecondaryRequestId(UUID.fromString(requestId)).ifPresentOrElse( -// ecsTlr -> handleRequestUpdateEvent(ecsTlr, event), -// () -> log.info("handleSecondaryRequestUpdate: ECS TLR for request {} not found", requestId)); - } - - private void handleRequestUpdateEvent(EcsTlrEntity ecsTlr, KafkaEvent event) { - log.debug("handleRequestUpdateEvent:: ecsTlr={}", () -> ecsTlr); - Request updatedRequest = event.getData().getNewVersion(); - - if (!requestMatchesEcsTlr(ecsTlr, updatedRequest, event.getTenantIdHeaderValue())) { - return; - } - if (updatedRequest.getEcsRequestPhase() == PRIMARY) { - handlePrimaryRequestUpdate(ecsTlr, event); - } - if (updatedRequest.getEcsRequestPhase() == SECONDARY) { - handleSecondaryRequestUpdate(ecsTlr, event); - } - } - - private static boolean requestMatchesEcsTlr(EcsTlrEntity ecsTlr, Request updatedRequest, - String updatedRequestTenant) { - - final EcsRequestPhaseEnum updatedRequestPhase = updatedRequest.getEcsRequestPhase(); - final UUID updatedRequestId = UUID.fromString(updatedRequest.getId()); - - if (updatedRequestPhase == PRIMARY && updatedRequestId.equals(ecsTlr.getPrimaryRequestId()) - && updatedRequestTenant.equals(ecsTlr.getPrimaryRequestTenantId())) { - log.info("requestMatchesEcsTlr:: updated primary request matches ECS TLR"); - return true; - } else if (updatedRequestPhase == SECONDARY && updatedRequestId.equals(ecsTlr.getSecondaryRequestId()) - && updatedRequestTenant.equals(ecsTlr.getSecondaryRequestTenantId())) { - log.info("requestMatchesEcsTlr:: updated secondary request matches ECS TLR"); - return true; - } - log.warn("requestMatchesEcsTlr:: request does not match ECS TLR: updatedRequestPhase={}, " + - "updatedRequestId={}, updatedRequestTenant={}, ecsTlr={}", updatedRequestPhase, - updatedRequestId, updatedRequestTenant, ecsTlr); - return false; + private void handleLoanCreationEvent(KafkaEvent event) { + log.info("handleLoanUpdateEvent:: handling loan creation event: {}", event::getId); } - private void handlePrimaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) { - propagateChangesFromPrimaryToSecondaryRequest(ecsTlr, event); - updateTransactionStatuses(event, ecsTlr); - } - - private void handleSecondaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) { - processItemIdUpdate(ecsTlr, event.getData().getNewVersion()); - updateTransactionStatuses(event, ecsTlr); - } - - private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) { - if (ecsTlr.getItemId() != null) { - log.info("processItemIdUpdate:: ECS TLR {} already has itemId {}", ecsTlr::getId, ecsTlr::getItemId); - return; - } - log.info("processItemIdUpdate:: updating ECS TLR {} with itemId {}", ecsTlr::getId, - updatedRequest::getItemId); - ecsTlr.setItemId(UUID.fromString(updatedRequest.getItemId())); - // TODO: change this if Page request works - dcbService.createTransactions(ecsTlr, updatedRequest); - ecsTlrRepository.save(ecsTlr); - log.info("processItemIdUpdate: ECS TLR {} is updated", ecsTlr::getId); - } - - private static Optional determineNewTransactionStatus( - KafkaEvent event) { - - final Request.StatusEnum oldRequestStatus = event.getData().getOldVersion().getStatus(); - final Request.StatusEnum newRequestStatus = event.getData().getNewVersion().getStatus(); - log.info("determineNewTransactionStatus:: oldRequestStatus='{}', newRequestStatus='{}'", - oldRequestStatus, newRequestStatus); - - if (newRequestStatus == oldRequestStatus) { - log.info("determineNewTransactionStatus:: request status did not change"); - return Optional.empty(); - } - - var newTransactionStatus = Optional.ofNullable( - switch (newRequestStatus) { - case OPEN_IN_TRANSIT -> OPEN; - case OPEN_AWAITING_PICKUP -> AWAITING_PICKUP; - case CLOSED_FILLED -> ITEM_CHECKED_OUT; - case CLOSED_CANCELLED -> CANCELLED; - default -> null; - }); - - newTransactionStatus.ifPresentOrElse( - ts -> log.info("determineNewTransactionStatus:: new transaction status: {}", ts), - () -> log.info("determineNewTransactionStatus:: irrelevant request status change")); - - return newTransactionStatus; - } - - private void updateTransactionStatuses(KafkaEvent event, EcsTlrEntity ecsTlr) { - determineNewTransactionStatus(event) - .ifPresent(newStatus -> updateTransactionStatuses(newStatus, ecsTlr)); - } - - private void updateTransactionStatuses(TransactionStatus.StatusEnum newStatus, EcsTlrEntity ecsTlr) { - log.info("updateTransactionStatuses:: updating primary transaction status to {}", newStatus::getValue); - updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newStatus, - ecsTlr.getPrimaryRequestTenantId()); - - log.info("updateTransactionStatuses:: updating intermediate transaction status to {}", newStatus::getValue); - updateTransactionStatus(ecsTlr.getIntermediateRequestDcbTransactionId(), newStatus, - ecsTlr.getIntermediateRequestTenantId()); - - log.info("updateTransactionStatuses:: updating secondary transaction status to {}", newStatus::getValue); - updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newStatus, - ecsTlr.getSecondaryRequestTenantId()); - } - - private void updateTransactionStatus(UUID transactionId, - TransactionStatus.StatusEnum newStatus, String tenantId) { - - if (transactionId == null) { - log.info("updateTransactionStatus:: transaction ID is null, doing nothing"); - return; - } - if (tenantId == null) { - log.info("updateTransactionStatus:: tenant ID is null, doing nothing"); - return; - } - - try { - var currentStatus = dcbService.getTransactionStatus(transactionId, tenantId).getStatus(); - log.info("updateTransactionStatus:: current transaction status: {}", currentStatus); - if (newStatus.getValue().equals(currentStatus.getValue())) { - log.info("updateTransactionStatus:: transaction status did not change, doing nothing"); - return; - } - log.info("updateTransactionStatus: changing status of transaction {} in tenant {} from {} to {}", - transactionId, tenantId, currentStatus.getValue(), newStatus.getValue()); - dcbService.updateTransactionStatus(transactionId, newStatus, tenantId); - } catch (FeignException.NotFound e) { - log.error("updateTransactionStatus:: transaction {} not found: {}", transactionId, e.getMessage()); - } catch (Exception e) { - log.error("updateTransactionStatus:: failed to update transaction status: {}", e::getMessage); - log.debug("updateTransactionStatus:: ", e); - } - } - - private void propagateChangesFromPrimaryToSecondaryRequest(EcsTlrEntity ecsTlr, - KafkaEvent event) { - - String secondaryRequestId = ecsTlr.getSecondaryRequestId().toString(); - String secondaryRequestTenantId = ecsTlr.getSecondaryRequestTenantId(); - Request primaryRequest = event.getData().getNewVersion(); - Request secondaryRequest = requestService.getRequestFromStorage( - secondaryRequestId, secondaryRequestTenantId); - - boolean shouldUpdateSecondaryRequest = false; - if (valueIsNotEqual(primaryRequest, secondaryRequest, Request::getRequestExpirationDate)) { - Date requestExpirationDate = primaryRequest.getRequestExpirationDate(); - log.info("propagateChangesFromPrimaryToSecondaryRequest:: request expiration date changed: {}", - requestExpirationDate); - secondaryRequest.setRequestExpirationDate(requestExpirationDate); - shouldUpdateSecondaryRequest = true; - } - if (valueIsNotEqual(primaryRequest, secondaryRequest, Request::getFulfillmentPreference)) { - FulfillmentPreferenceEnum fulfillmentPreference = primaryRequest.getFulfillmentPreference(); - log.info("propagateChangesFromPrimaryToSecondaryRequest:: fulfillment preference changed: {}", - fulfillmentPreference); - secondaryRequest.setFulfillmentPreference(fulfillmentPreference); - shouldUpdateSecondaryRequest = true; - } - if (valueIsNotEqual(primaryRequest, secondaryRequest, Request::getPickupServicePointId)) { - String pickupServicePointId = primaryRequest.getPickupServicePointId(); - log.info("propagateChangesFromPrimaryToSecondaryRequest:: pickup service point ID changed: {}", - pickupServicePointId); - secondaryRequest.setPickupServicePointId(pickupServicePointId); - shouldUpdateSecondaryRequest = true; - clonePickupServicePoint(ecsTlr, pickupServicePointId); - } - - if (!shouldUpdateSecondaryRequest) { - log.info("propagateChangesFromPrimaryToSecondaryRequest:: no relevant changes detected"); - return; - } - - log.info("propagateChangesFromPrimaryToSecondaryRequest:: updating secondary request"); - requestService.updateRequestInStorage(secondaryRequest, secondaryRequestTenantId); - log.info("propagateChangesFromPrimaryToSecondaryRequest:: secondary request updated"); - } - - private void clonePickupServicePoint(EcsTlrEntity ecsTlr, String pickupServicePointId) { - if (pickupServicePointId == null) { - log.info("clonePickupServicePoint:: pickupServicePointId is null, doing nothing"); - return; - } - log.info("clonePickupServicePoint:: ensuring that service point {} exists in lending tenant", - pickupServicePointId); - ServicePoint pickupServicePoint = executionService.executeSystemUserScoped( - ecsTlr.getPrimaryRequestTenantId(), () -> servicePointService.find(pickupServicePointId)); - executionService.executeSystemUserScoped(ecsTlr.getSecondaryRequestTenantId(), - () -> servicePointCloningService.clone(pickupServicePoint)); + private void handleLoanUpdateEvent(KafkaEvent event) { + log.info("handleLoanUpdateEvent:: handling loan update event: {}", event::getId); } - private static boolean valueIsNotEqual(T o1, T o2, Function valueExtractor) { - return !Objects.equals(valueExtractor.apply(o1), valueExtractor.apply(o2)); - } } diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index 869bac9a..c3dbdbb9 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -26,7 +26,6 @@ import org.folio.domain.dto.User; import org.folio.exception.RequestCreatingException; import org.folio.service.CloningService; -import org.folio.service.ConsortiaService; import org.folio.service.RequestService; import org.folio.service.ServicePointService; import org.folio.service.UserService; @@ -54,8 +53,6 @@ public class RequestServiceImpl implements RequestService { private final ServicePointService servicePointService; private final CloningService userCloningService; private final CloningService servicePointCloningService; - private final ConsortiaService consortiaService; - private final UserTenantsServiceImpl userTenantsService; private final SystemUserScopedExecutionService systemUserScopedExecutionService; public static final String HOLDINGS_RECORD_ID = "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9"; diff --git a/src/test/java/org/folio/api/EcsTlrApiTest.java b/src/test/java/org/folio/api/EcsTlrApiTest.java index bd1aff49..13e9578f 100644 --- a/src/test/java/org/folio/api/EcsTlrApiTest.java +++ b/src/test/java/org/folio/api/EcsTlrApiTest.java @@ -220,7 +220,7 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques // 1.5 Mock DCB endpoints DcbTransaction borrowerTransactionPostRequest = new DcbTransaction() - .role(DcbTransaction.RoleEnum.BORROWER) + .role(DcbTransaction.RoleEnum.BORROWING_PICKUP) .item(new DcbItem() .id(ITEM_ID) .barcode(ITEM_BARCODE) diff --git a/src/test/java/org/folio/controller/KafkaEventListenerTest.java b/src/test/java/org/folio/controller/KafkaEventListenerTest.java index f3d9b31d..8e896c79 100644 --- a/src/test/java/org/folio/controller/KafkaEventListenerTest.java +++ b/src/test/java/org/folio/controller/KafkaEventListenerTest.java @@ -564,7 +564,7 @@ private static void verifyThatDcbTransactionsWereCreated(EcsTlrEntity ecsTlr) { assertNotNull(secondaryRequestDcbTransactionId); DcbTransaction expectedBorrowerTransaction = new DcbTransaction() - .role(DcbTransaction.RoleEnum.BORROWER) + .role(DcbTransaction.RoleEnum.BORROWING_PICKUP) .item(new DcbItem() .id(ecsTlr.getItemId().toString()) .barcode("test") diff --git a/src/test/java/org/folio/service/EcsTlrServiceTest.java b/src/test/java/org/folio/service/EcsTlrServiceTest.java index b741d028..34db8c46 100644 --- a/src/test/java/org/folio/service/EcsTlrServiceTest.java +++ b/src/test/java/org/folio/service/EcsTlrServiceTest.java @@ -46,6 +46,8 @@ class EcsTlrServiceTest { private TenantService tenantService; @Mock private DcbService dcbService; + @Mock + private UserTenantsService userTenantsService; @Spy private final EcsTlrMapper ecsTlrMapper = new EcsTlrMapperImpl(); @@ -99,6 +101,7 @@ void ecsTlrShouldBeCreatedThenUpdatedAndDeleted(EcsTlr.RequestLevelEnum requestL .id(UUID.randomUUID().toString()) .itemId(UUID.randomUUID().toString()); + when(userTenantsService.getCentralTenantId()).thenReturn(borrowingTenant); when(ecsTlrRepository.save(any(EcsTlrEntity.class))).thenReturn(mockEcsTlrEntity); when(tenantService.getPrimaryRequestTenantId(any(EcsTlrEntity.class))) .thenReturn(borrowingTenant); @@ -140,7 +143,7 @@ void canNotCreateEcsTlrWhenFailedToGetBorrowingTenantId() { TenantPickingException exception = assertThrows(TenantPickingException.class, () -> ecsTlrService.create(ecsTlr)); - assertEquals("Failed to get borrowing tenant", exception.getMessage()); + assertEquals("Failed to get primary request tenant", exception.getMessage()); } @Test @@ -155,6 +158,6 @@ void canNotCreateEcsTlrWhenFailedToGetLendingTenants() { TenantPickingException exception = assertThrows(TenantPickingException.class, () -> ecsTlrService.create(ecsTlr)); - assertEquals("Failed to find lending tenants for instance " + instanceId, exception.getMessage()); + assertEquals("Failed to find secondary request tenants for instance " + instanceId, exception.getMessage()); } } From 565b4d9bfd6dc656699e4d39cd4fbab22a33ed4c Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Mon, 9 Dec 2024 14:04:38 +0200 Subject: [PATCH 26/30] MODTLR-98 Remove redundant changes --- .../listener/kafka/KafkaEventListener.java | 29 +-- .../org/folio/service/ConsortiaService.java | 5 - .../org/folio/service/UserTenantsService.java | 1 - .../service/impl/ConsortiaServiceImpl.java | 35 ---- .../folio/service/impl/LoanEventHandler.java | 40 ----- src/main/resources/swagger.api/ecs-tlr.yaml | 2 - .../resources/swagger.api/schemas/loan.json | 166 ------------------ 7 files changed, 5 insertions(+), 273 deletions(-) delete mode 100644 src/main/java/org/folio/service/impl/LoanEventHandler.java delete mode 100644 src/main/resources/swagger.api/schemas/loan.json diff --git a/src/main/java/org/folio/listener/kafka/KafkaEventListener.java b/src/main/java/org/folio/listener/kafka/KafkaEventListener.java index dc0f9a05..f6e7b840 100644 --- a/src/main/java/org/folio/listener/kafka/KafkaEventListener.java +++ b/src/main/java/org/folio/listener/kafka/KafkaEventListener.java @@ -5,14 +5,12 @@ import java.nio.charset.StandardCharsets; import java.util.Optional; -import org.folio.domain.dto.Loan; import org.folio.domain.dto.Request; import org.folio.domain.dto.RequestsBatchUpdate; import org.folio.domain.dto.User; import org.folio.domain.dto.UserGroup; import org.folio.exception.KafkaEventDeserializationException; import org.folio.service.KafkaEventHandler; -import org.folio.service.impl.LoanEventHandler; import org.folio.service.impl.RequestBatchUpdateEventHandler; import org.folio.service.impl.RequestEventHandler; import org.folio.service.impl.UserEventHandler; @@ -36,22 +34,18 @@ public class KafkaEventListener { private static final ObjectMapper objectMapper = new ObjectMapper(); private final RequestEventHandler requestEventHandler; - private final LoanEventHandler loanEventHandler; private final UserGroupEventHandler userGroupEventHandler; private final UserEventHandler userEventHandler; private final SystemUserScopedExecutionService systemUserScopedExecutionService; private final RequestBatchUpdateEventHandler requestBatchEventHandler; - @Autowired - public KafkaEventListener(RequestEventHandler requestEventHandler, - LoanEventHandler loanEventHandler, - RequestBatchUpdateEventHandler requestBatchEventHandler, - SystemUserScopedExecutionService systemUserScopedExecutionService, - UserGroupEventHandler userGroupEventHandler, - UserEventHandler userEventHandler) { + public KafkaEventListener(@Autowired RequestEventHandler requestEventHandler, + @Autowired RequestBatchUpdateEventHandler requestBatchEventHandler, + @Autowired SystemUserScopedExecutionService systemUserScopedExecutionService, + @Autowired UserGroupEventHandler userGroupEventHandler, + @Autowired UserEventHandler userEventHandler) { this.requestEventHandler = requestEventHandler; - this.loanEventHandler = loanEventHandler; this.systemUserScopedExecutionService = systemUserScopedExecutionService; this.userGroupEventHandler = userGroupEventHandler; this.requestBatchEventHandler = requestBatchEventHandler; @@ -82,19 +76,6 @@ public void handleRequestBatchUpdateEvent(String eventString, MessageHeaders mes log.info("handleRequestBatchUpdateEvent:: event consumed: {}", event::getId); } - @KafkaListener( - topicPattern = "${folio.environment}\\.\\w+\\.circulation\\.loan", - groupId = "${spring.kafka.consumer.group-id}" - ) - public void handleLoanEvent(String eventString, MessageHeaders messageHeaders) { - log.debug("handleLoanEvent:: event: {}", () -> eventString); - KafkaEvent event = deserialize(eventString, messageHeaders, Loan.class); - log.info("handleLoanEvent:: event received: {}", event::getId); - log.info("handleLoanEvent:: event: {}", eventString); - handleEvent(event, loanEventHandler); - log.info("handleLoanEvent:: event consumed: {}", event::getId); - } - private void handleEvent(KafkaEvent event, KafkaEventHandler handler) { try { systemUserScopedExecutionService.executeAsyncSystemUserScoped(CENTRAL_TENANT_ID, diff --git a/src/main/java/org/folio/service/ConsortiaService.java b/src/main/java/org/folio/service/ConsortiaService.java index 932c54cb..562d9749 100644 --- a/src/main/java/org/folio/service/ConsortiaService.java +++ b/src/main/java/org/folio/service/ConsortiaService.java @@ -6,11 +6,6 @@ import org.folio.domain.dto.TenantCollection; public interface ConsortiaService { - TenantCollection getAllDataTenants(String consortiumId); - -// boolean isCurrentTenantCentral(); - -// T executeInTenant(String tenantId, Callable action); TenantCollection getAllConsortiumTenants(String consortiumId); Collection getAllConsortiumTenants(); } diff --git a/src/main/java/org/folio/service/UserTenantsService.java b/src/main/java/org/folio/service/UserTenantsService.java index bdfaaecc..67de47e4 100644 --- a/src/main/java/org/folio/service/UserTenantsService.java +++ b/src/main/java/org/folio/service/UserTenantsService.java @@ -4,6 +4,5 @@ public interface UserTenantsService { UserTenant findFirstUserTenant(); - String getCentralTenantId(); } diff --git a/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java b/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java index 7f44b824..e328de0b 100644 --- a/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java +++ b/src/main/java/org/folio/service/impl/ConsortiaServiceImpl.java @@ -11,7 +11,6 @@ import org.folio.domain.dto.UserTenant; import org.folio.service.ConsortiaService; import org.folio.service.UserTenantsService; -import org.folio.spring.service.SystemUserScopedExecutionService; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -24,11 +23,6 @@ public class ConsortiaServiceImpl implements ConsortiaService { private final ConsortiaClient consortiaClient; private final UserTenantsService userTenantsService; - @Override - public TenantCollection getAllDataTenants(String consortiumId) { - return consortiaClient.getConsortiaTenants(consortiumId); - } - @Override public TenantCollection getAllConsortiumTenants(String consortiumId) { return consortiaClient.getConsortiaTenants(consortiumId); @@ -46,33 +40,4 @@ public Collection getAllConsortiumTenants() { log.info("getAllConsortiumTenants:: found {} consortium tenants", tenants::size); return tenants; } - -// @Override -// public boolean isCurrentTenantCentral() { -// var userTenant = userTenantsService.findFirstUserTenant(); -// var centralTenantId = userTenant.getCentralTenantId(); -// var currentTenantId = userTenant.getTenantId(); -// -// if (centralTenantId == null || currentTenantId == null) { -// log.warn("isCurrentTenantCentral:: Cannot determine central tenant or current tenant"); -// return false; -// } -// -// return centralTenantId.equals(currentTenantId); -// } -// -// @Override -// public T executeInTenant(String tenantId, Callable action) { -// if (isCurrentTenantCentral()) { -// try { -// return action.call(); -// } catch (Exception e) { -// log.info("executeInTenant:: Failed to execute in Central tenant"); -// return null; -// } -// } else { -// return systemUserScopedExecutionService.executeSystemUserScoped( -// tenantId, action); -// } -// } } diff --git a/src/main/java/org/folio/service/impl/LoanEventHandler.java b/src/main/java/org/folio/service/impl/LoanEventHandler.java deleted file mode 100644 index dc2dc630..00000000 --- a/src/main/java/org/folio/service/impl/LoanEventHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.folio.service.impl; - -import static org.folio.support.KafkaEvent.EventType.CREATED; -import static org.folio.support.KafkaEvent.EventType.UPDATED; - -import org.folio.domain.dto.Loan; -import org.folio.service.KafkaEventHandler; -import org.folio.support.KafkaEvent; -import org.springframework.stereotype.Service; - -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; - -@AllArgsConstructor -@Service -@Log4j2 -public class LoanEventHandler implements KafkaEventHandler { - - @Override - public void handle(KafkaEvent event) { - log.info("handle:: processing loan event: {}", event::getId); - if (event.getType() == CREATED) { - handleLoanCreationEvent(event); - } else if (event.getType() == UPDATED) { - handleLoanUpdateEvent(event); - } else { - log.info("handle:: ignoring event {} of unsupported type: {}", event::getId, event::getType); - } - log.info("handle:: loan event processed: {}", event::getId); - } - - private void handleLoanCreationEvent(KafkaEvent event) { - log.info("handleLoanUpdateEvent:: handling loan creation event: {}", event::getId); - } - - private void handleLoanUpdateEvent(KafkaEvent event) { - log.info("handleLoanUpdateEvent:: handling loan update event: {}", event::getId); - } - -} diff --git a/src/main/resources/swagger.api/ecs-tlr.yaml b/src/main/resources/swagger.api/ecs-tlr.yaml index b1d4460c..dd60c16e 100644 --- a/src/main/resources/swagger.api/ecs-tlr.yaml +++ b/src/main/resources/swagger.api/ecs-tlr.yaml @@ -103,8 +103,6 @@ components: $ref: 'schemas/request.json' requests: $ref: 'schemas/requests.json' - loan: - $ref: 'schemas/loan.json' searchInstancesResponse: $ref: 'schemas/search/searchInstancesResponse.yaml' searchItemResponse: diff --git a/src/main/resources/swagger.api/schemas/loan.json b/src/main/resources/swagger.api/schemas/loan.json deleted file mode 100644 index 1ab9653f..00000000 --- a/src/main/resources/swagger.api/schemas/loan.json +++ /dev/null @@ -1,166 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "title": "Loan", - "description": "Links the item with the patron and applies certain conditions based on policies", - "properties": { - "id": { - "description": "Unique ID (generated UUID) of the loan", - "type": "string" - }, - "userId": { - "description": "ID of the patron the item was lent to. Required for open loans, not required for closed loans (for anonymization).", - "type": "string" - }, - "proxyUserId": { - "description": "ID of the user representing a proxy for the patron", - "type": "string", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "itemId": { - "description": "ID of the item lent to the patron", - "type": "string" - }, - "itemEffectiveLocationIdAtCheckOut": { - "description": "The effective location, at the time of checkout, of the item loaned to the patron.", - "type": "string", - "$ref": "uuid.json" - }, - "status": { - "description": "Overall status of the loan", - "type": "object", - "properties": { - "name": { - "description": "Name of the status (currently can be any value, values commonly used are Open and Closed)", - "type": "string" - } - } - }, - "loanDate": { - "description": "Date time when the loan began (typically represented according to rfc3339 section-5.6. Has not had the date-time format validation applied as was not supported at point of introduction and would now be a breaking change)", - "type": "string" - }, - "dueDate": { - "description": "Date time when the item is due to be returned", - "type": "string", - "format": "date-time" - }, - "returnDate": { - "description": "Date time when the item is returned and the loan ends (typically represented according to rfc3339 section-5.6. Has not had the date-time format validation applied as was not supported at point of introduction and would now be a breaking change)", - "type": "string" - }, - "systemReturnDate" : { - "description": "Date time when the returned item is actually processed", - "type": "string", - "format": "date-time" - }, - "action": { - "description": "Last action performed on a loan (currently can be any value, values commonly used are checkedout and checkedin)", - "type": "string" - }, - "actionComment": { - "description": "Comment to last action performed on a loan", - "type": "string" - }, - "itemStatus": { - "description": "Last item status used in relation to this loan (currently can be any value, values commonly used are Checked out and Available)", - "type": "string" - }, - "renewalCount": { - "description": "Count of how many times a loan has been renewed (incremented by the client)", - "type": "integer" - }, - "loanPolicyId": { - "description": "ID of last policy used in relation to this loan", - "type": "string" - }, - "checkoutServicePointId": { - "description": "ID of the Service Point where the last checkout occured", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", - "type": "string" - }, - "checkinServicePointId": { - "description": "ID of the Service Point where the last checkin occured", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", - "type": "string" - }, - "patronGroupIdAtCheckout": { - "description": "Patron Group Id at checkout", - "type": "string" - }, - "dueDateChangedByRecall": { - "description": "Indicates whether or not this loan had its due date modified by a recall on the loaned item", - "type": "boolean" - }, - "isDcb": { - "description": "Indicates whether or not this loan is associated for DCB use case", - "type": "boolean" - }, - "declaredLostDate" : { - "description": "Date and time the item was declared lost during this loan", - "type": "string", - "format": "date-time" - }, - "claimedReturnedDate": { - "description": "Date and time the item was claimed returned for this loan", - "type": "string", - "format": "date-time" - }, - "overdueFinePolicyId": { - "description": "ID of overdue fines policy at the time the item is check-in or renewed", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", - "type": "string" - }, - "lostItemPolicyId": { - "description": "ID of lost item policy which determines when the item ages to lost and the associated fees or the associated fees if the patron declares the item lost.", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", - "type": "string" - }, - "metadata": { - "description": "Metadata about creation and changes to loan, provided by the server (client should not provide)", - "type": "object", - "$ref": "metadata.json" - }, - "agedToLostDelayedBilling": { - "description": "Aged to Lost Delayed Billing processing", - "type": "object", - "properties": { - "lostItemHasBeenBilled": { - "description": "Indicates if the aged to lost fee has been billed (for use where delayed billing is set up)", - "type": "boolean" - }, - "dateLostItemShouldBeBilled": { - "description": "Indicates when the aged to lost fee should be billed (for use where delayed billing is set up)", - "type": "string", - "format": "date-time" - }, - "agedToLostDate": { - "description": "Date and time the item was aged to lost for this loan", - "type": "string", - "format": "date-time" - } - } - }, - "reminders" : { - "description": "Information about reminders for overdue loan", - "type": "object", - "properties": { - "lastFeeBilled": { - "description": "Information about the most recent reminder fee billing", - "type": "object", - "properties": { - "number": { - "description": "Last reminder fee billed, sequence number", - "type": "integer" - }, - "date": { - "description": "Last reminder fee billed, date", - "type": "string", - "format": "date-time" - } - } - } - } - } - } -} \ No newline at end of file From e8b1913cb9836815a8829ab4e80b2ec6e9dab554 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Mon, 9 Dec 2024 14:17:02 +0200 Subject: [PATCH 27/30] MODTLR-98 Fix RequestServiceTest --- .../service/impl/RequestServiceImpl.java | 11 +- .../listener/KafkaEventListenerTest.java | 7 +- .../org/folio/service/RequestServiceTest.java | 144 ++++++------------ 3 files changed, 59 insertions(+), 103 deletions(-) diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index c3dbdbb9..b876d286 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -177,7 +177,16 @@ public RequestWrapper createIntermediateRequest(Request intermediateRequest, throw new RequestCreatingException(errorMessage); } - private CirculationItem createCirculationItem(Request request, String inventoryTenantId) { + public CirculationItem createCirculationItem(Request request, String inventoryTenantId) { + if (request == null) { + log.warn("createCirculationItem:: request is null, skipping"); + return null; + } + if (inventoryTenantId == null) { + log.warn("createCirculationItem:: inventory tenant ID is null, skipping"); + return null; + } + String itemId = request.getItemId(); String instanceId = request.getInstanceId(); String pickupLocation = request.getPickupServicePointId(); diff --git a/src/test/java/org/folio/listener/KafkaEventListenerTest.java b/src/test/java/org/folio/listener/KafkaEventListenerTest.java index fe5f8f5d..759f8272 100644 --- a/src/test/java/org/folio/listener/KafkaEventListenerTest.java +++ b/src/test/java/org/folio/listener/KafkaEventListenerTest.java @@ -8,7 +8,6 @@ import java.util.Map; import org.folio.listener.kafka.KafkaEventListener; -import org.folio.service.impl.LoanEventHandler; import org.folio.service.impl.RequestBatchUpdateEventHandler; import org.folio.service.impl.RequestEventHandler; import org.folio.service.impl.UserEventHandler; @@ -25,8 +24,6 @@ class KafkaEventListenerTest { @Mock RequestEventHandler requestEventHandler; @Mock - LoanEventHandler loanEventHandler; - @Mock RequestBatchUpdateEventHandler requestBatchEventHandler; @Mock SystemUserScopedExecutionService systemUserScopedExecutionService; @@ -40,8 +37,8 @@ void shouldHandleExceptionInEventHandler() { doThrow(new NullPointerException("NPE")).when(systemUserScopedExecutionService) .executeAsyncSystemUserScoped(any(), any()); KafkaEventListener kafkaEventListener = new KafkaEventListener(requestEventHandler, - loanEventHandler, requestBatchEventHandler, systemUserScopedExecutionService, - userGroupEventHandler, userEventHandler); + requestBatchEventHandler, systemUserScopedExecutionService, userGroupEventHandler, + userEventHandler); kafkaEventListener.handleRequestEvent("{}", new MessageHeaders(Map.of(TENANT, "default".getBytes()))); diff --git a/src/test/java/org/folio/service/RequestServiceTest.java b/src/test/java/org/folio/service/RequestServiceTest.java index b54e3976..05905021 100644 --- a/src/test/java/org/folio/service/RequestServiceTest.java +++ b/src/test/java/org/folio/service/RequestServiceTest.java @@ -55,107 +55,57 @@ void setUp() { any(Runnable.class)); } -// @Test -// void shouldReturnNullIfEcsTlrOrSecondaryRequestIsNull() { -// assertNull(requestService.createCirculationItem(null, secondaryRequest, BORROWER_ID, LENDER_ID)); -// assertNull(requestService.createCirculationItem(ecsTlrEntity, null, BORROWER_ID, LENDER_ID)); -// } -// -// @Test -// void shouldReturnNullIfItemIdOrInstanceIdIsNull() { -// secondaryRequest.setItemId(null); -// assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); -// -// secondaryRequest.setItemId(ITEM_ID); -// secondaryRequest.setInstanceId(null); -// assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); -// } -// -// @Test -// void shouldReturnExistingCirculationItemIfFound() { -// CirculationItem existingItem = new CirculationItem(); -// when(circulationItemClient.getCirculationItem(any())).thenReturn(existingItem); -// -// assertEquals(existingItem, requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); -// } + @Test + void shouldReturnNullIfRequestIsNull() { + assertNull(requestService.createCirculationItem(null, LENDER_ID)); + } + + @Test + void shouldReturnNullIfItemIdOrInstanceIdIsNull() { + secondaryRequest.setItemId(null); + assertNull(requestService.createCirculationItem(secondaryRequest, LENDER_ID)); + + secondaryRequest.setItemId(ITEM_ID); + secondaryRequest.setInstanceId(null); + assertNull(requestService.createCirculationItem(secondaryRequest, LENDER_ID)); + } + + @Test + void shouldReturnExistingCirculationItemIfFound() { + CirculationItem existingItem = new CirculationItem(); + when(circulationItemClient.getCirculationItem(any())).thenReturn(existingItem); -// @Test -// void shouldCreateCirculationItem() { -// when(circulationItemClient.getCirculationItem(any())).thenReturn(null); -// when(circulationItemClient.createCirculationItem(any(), any())).thenReturn(new CirculationItem()); -// -// InventoryItem item = new InventoryItem(); -// item.setStatus(new InventoryItemStatus((InventoryItemStatus.NameEnum.PAGED))); -// when(requestService.getItemFromStorage(eq(ITEM_ID), anyString())).thenReturn(item); -// -// String instanceTitle = "Title"; -// InventoryInstance instance = new InventoryInstance(); -// instance.setTitle(instanceTitle); -// when(requestService.getInstanceFromStorage(eq(INSTANCE_ID), anyString())).thenReturn(instance); -// -// CirculationItem expectedCirculationItem = new CirculationItem() -// .status(new CirculationItemStatus() -// .name(CirculationItemStatus.NameEnum.AVAILABLE)) -// .id(UUID.fromString(ITEM_ID)) -// .holdingsRecordId(UUID.fromString(HOLDINGS_RECORD_ID)) -// .dcbItem(true) -// .instanceTitle(instanceTitle) -// .lendingLibraryCode(LENDING_LIBRARY_CODE); -// requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID); -// verify(circulationItemClient).createCirculationItem(ITEM_ID, expectedCirculationItem); -// } + assertEquals(existingItem, requestService.createCirculationItem(secondaryRequest, LENDER_ID)); + } + + @Test + void shouldCreateCirculationItem() { + when(circulationItemClient.getCirculationItem(any())).thenReturn(null); + when(circulationItemClient.createCirculationItem(any(), any())).thenReturn(new CirculationItem()); + + InventoryItem item = new InventoryItem(); + item.setStatus(new InventoryItemStatus((InventoryItemStatus.NameEnum.PAGED))); + when(requestService.getItemFromStorage(eq(ITEM_ID), anyString())).thenReturn(item); + + String instanceTitle = "Title"; + InventoryInstance instance = new InventoryInstance(); + instance.setTitle(instanceTitle); + when(requestService.getInstanceFromStorage(eq(INSTANCE_ID), anyString())).thenReturn(instance); + + CirculationItem expectedCirculationItem = new CirculationItem() + .status(new CirculationItemStatus() + .name(CirculationItemStatus.NameEnum.AVAILABLE)) + .id(UUID.fromString(ITEM_ID)) + .holdingsRecordId(UUID.fromString(HOLDINGS_RECORD_ID)) + .dcbItem(true) + .instanceTitle(instanceTitle) + .lendingLibraryCode(LENDING_LIBRARY_CODE); + requestService.createCirculationItem(secondaryRequest, LENDER_ID); + verify(circulationItemClient).createCirculationItem(ITEM_ID, expectedCirculationItem); + } @Test void circulationItemUpdateShouldBeSkippedWhenNull() { assertNull(requestService.updateCirculationItemOnRequestCreation(null, null)); } -// @Test -// void shouldReturnNullIfEcsTlrOrSecondaryRequestIsNull() { -// assertNull(requestService.createCirculationItem(null, secondaryRequest, BORROWER_ID, LENDER_ID)); -// assertNull(requestService.createCirculationItem(ecsTlrEntity, null, BORROWER_ID, LENDER_ID)); -// } -// -// @Test -// void shouldReturnNullIfItemIdOrInstanceIdIsNull() { -// secondaryRequest.setItemId(null); -// assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); -// -// secondaryRequest.setItemId(ITEM_ID); -// secondaryRequest.setInstanceId(null); -// assertNull(requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); -// } -// -// @Test -// void shouldReturnExistingCirculationItemIfFound() { -// CirculationItem existingItem = new CirculationItem(); -// when(circulationItemClient.getCirculationItem(any())).thenReturn(existingItem); -// -// assertEquals(existingItem, requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID)); -// } -// -// @Test -// void shouldCreateCirculationItem() { -// when(circulationItemClient.getCirculationItem(any())).thenReturn(null); -// when(circulationItemClient.createCirculationItem(any(), any())).thenReturn(new CirculationItem()); -// -// InventoryItem item = new InventoryItem(); -// item.setStatus(new InventoryItemStatus((InventoryItemStatus.NameEnum.PAGED))); -// when(requestService.getItemFromStorage(eq(ITEM_ID), anyString())).thenReturn(item); -// -// String instanceTitle = "Title"; -// InventoryInstance instance = new InventoryInstance(); -// instance.setTitle(instanceTitle); -// when(requestService.getInstanceFromStorage(eq(INSTANCE_ID), anyString())).thenReturn(instance); -// -// CirculationItem expectedCirculationItem = new CirculationItem() -// .status(new CirculationItemStatus() -// .name(CirculationItemStatus.NameEnum.AVAILABLE)) -// .id(UUID.fromString(ITEM_ID)) -// .holdingsRecordId(UUID.fromString(HOLDINGS_RECORD_ID)) -// .dcbItem(true) -// .instanceTitle(instanceTitle) -// .lendingLibraryCode(LENDING_LIBRARY_CODE); -// requestService.createCirculationItem(ecsTlrEntity, secondaryRequest, BORROWER_ID, LENDER_ID); -// verify(circulationItemClient).createCirculationItem(ITEM_ID, expectedCirculationItem); -// } } From 795db044aaf4d023bd990ab53ac801f9e78b367f Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Mon, 9 Dec 2024 17:41:00 +0200 Subject: [PATCH 28/30] MODTLR-98 Extend integration test --- .../folio/service/impl/DcbServiceImpl.java | 28 ++--- .../folio/service/impl/EcsTlrServiceImpl.java | 24 ++-- .../java/org/folio/api/EcsTlrApiTest.java | 115 ++++++++++++------ 3 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java index 3106baf7..99017e46 100644 --- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java +++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java @@ -55,14 +55,7 @@ public void createLendingTransaction(EcsTlrEntity ecsTlr) { @Override public void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request) { log.info("createBorrowerTransaction:: creating borrower transaction for ECS TLR {}", ecsTlr::getId); - DcbItem dcbItem = new DcbItem() - .id(request.getItemId()) - .title(request.getInstance().getTitle()) - .barcode(request.getItem().getBarcode()); - DcbTransaction transaction = new DcbTransaction() - .requestId(ecsTlr.getIntermediateRequestId().toString()) - .item(dcbItem) - .role(BORROWER); + DcbTransaction transaction = buildTransaction(request, BORROWER, ecsTlr.getIntermediateRequestId()); final UUID transactionId = createTransaction(transaction, ecsTlr.getIntermediateRequestTenantId()); ecsTlr.setIntermediateRequestDcbTransactionId(transactionId); log.info("createBorrowerTransaction:: borrower transaction {} for ECS TLR {} created", @@ -73,7 +66,9 @@ public void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request) { public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request) { log.info("createBorrowingPickupTransaction:: creating borrowing-pickup transaction for ECS TLR {}", ecsTlr::getId); - final UUID transactionId = createPickupTransaction(ecsTlr, request, BORROWING_PICKUP); + DcbTransaction transaction = buildTransaction(request, BORROWING_PICKUP, ecsTlr.getPrimaryRequestId()); + final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); + ecsTlr.setPrimaryRequestDcbTransactionId(transactionId); log.info("createBorrowingPickupTransaction:: borrowing-pickup transaction {} for ECS TLR {} created", () -> transactionId, ecsTlr::getId); } @@ -81,24 +76,23 @@ public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request reques @Override public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request) { log.info("createPickupTransaction:: creating pickup transaction for ECS TLR {}", ecsTlr.getId()); - final UUID transactionId = createPickupTransaction(ecsTlr, request, PICKUP); + DcbTransaction transaction = buildTransaction(request, PICKUP, ecsTlr.getPrimaryRequestId()); + final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); + ecsTlr.setPrimaryRequestDcbTransactionId(transactionId); log.info("createPickupTransaction:: pickup transaction {} for ECS TLR {} created", () -> transactionId, ecsTlr::getId); } - private UUID createPickupTransaction(EcsTlrEntity ecsTlr, Request request, RoleEnum role) { + private DcbTransaction buildTransaction(Request request, RoleEnum role, UUID requestId) { DcbItem dcbItem = new DcbItem() .id(request.getItemId()) .title(request.getInstance().getTitle()) .barcode(request.getItem().getBarcode()); - DcbTransaction transaction = new DcbTransaction() - .requestId(ecsTlr.getPrimaryRequestId().toString()) + + return new DcbTransaction() + .requestId(requestId.toString()) .item(dcbItem) .role(role); - final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId()); - ecsTlr.setPrimaryRequestDcbTransactionId(transactionId); - - return transactionId; } private UUID createTransaction(DcbTransaction transaction, String tenantId) { diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 589a13ea..a9b3b702 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -1,6 +1,8 @@ package org.folio.service.impl; import static java.util.Optional.of; +import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.INTERMEDIATE; +import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.PRIMARY; import java.util.Collection; import java.util.List; @@ -11,6 +13,7 @@ import org.folio.domain.RequestWrapper; import org.folio.domain.dto.EcsTlr; import org.folio.domain.dto.Request; +import org.folio.domain.dto.Request.EcsRequestPhaseEnum; import org.folio.domain.entity.EcsTlrEntity; import org.folio.domain.mapper.EcsTlrMapper; import org.folio.exception.TenantPickingException; @@ -141,21 +144,14 @@ private EcsTlrEntity save(EcsTlrEntity ecsTlr) { } private static Request buildPrimaryRequest(Request secondaryRequest) { - return new Request() - .id(secondaryRequest.getId()) - .instanceId(secondaryRequest.getInstanceId()) - .itemId(secondaryRequest.getItemId()) - .holdingsRecordId(secondaryRequest.getHoldingsRecordId()) - .requesterId(secondaryRequest.getRequesterId()) - .requestDate(secondaryRequest.getRequestDate()) - .requestLevel(secondaryRequest.getRequestLevel()) - .requestType(secondaryRequest.getRequestType()) - .ecsRequestPhase(Request.EcsRequestPhaseEnum.PRIMARY) - .fulfillmentPreference(secondaryRequest.getFulfillmentPreference()) - .pickupServicePointId(secondaryRequest.getPickupServicePointId()); + return buildRequest(secondaryRequest, PRIMARY); } private static Request buildIntermediateRequest(Request secondaryRequest) { + return buildRequest(secondaryRequest, INTERMEDIATE); + } + + private static Request buildRequest(Request secondaryRequest, EcsRequestPhaseEnum ecsRequestPhase) { return new Request() .id(secondaryRequest.getId()) .instanceId(secondaryRequest.getInstanceId()) @@ -165,14 +161,14 @@ private static Request buildIntermediateRequest(Request secondaryRequest) { .requestDate(secondaryRequest.getRequestDate()) .requestLevel(secondaryRequest.getRequestLevel()) .requestType(secondaryRequest.getRequestType()) - .ecsRequestPhase(Request.EcsRequestPhaseEnum.INTERMEDIATE) + .ecsRequestPhase(ecsRequestPhase) .fulfillmentPreference(secondaryRequest.getFulfillmentPreference()) .pickupServicePointId(secondaryRequest.getPickupServicePointId()); } private Request buildSecondaryRequest(EcsTlrEntity ecsTlr) { return requestsMapper.mapEntityToRequest(ecsTlr) - .ecsRequestPhase(Request.EcsRequestPhaseEnum.SECONDARY); + .ecsRequestPhase(EcsRequestPhaseEnum.SECONDARY); } private static void updateEcsTlr(EcsTlrEntity ecsTlr, RequestWrapper primaryRequest, diff --git a/src/test/java/org/folio/api/EcsTlrApiTest.java b/src/test/java/org/folio/api/EcsTlrApiTest.java index 13e9578f..29abcb63 100644 --- a/src/test/java/org/folio/api/EcsTlrApiTest.java +++ b/src/test/java/org/folio/api/EcsTlrApiTest.java @@ -7,6 +7,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.jsonResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.not; import static com.github.tomakehurst.wiremock.client.WireMock.notFound; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; @@ -15,6 +16,8 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static org.folio.domain.dto.EcsTlr.RequestTypeEnum.HOLD; import static org.folio.domain.dto.EcsTlr.RequestTypeEnum.PAGE; +import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.INTERMEDIATE; +import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.PRIMARY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.NOT_FOUND; @@ -50,6 +53,7 @@ import org.junit.jupiter.params.provider.EnumSource; import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.client.WireMock; class EcsTlrApiTest extends BaseIT { private static final String ITEM_ID = randomId(); @@ -62,6 +66,7 @@ class EcsTlrApiTest extends BaseIT { private static final String REQUESTER_BARCODE = randomId(); private static final String SECONDARY_REQUEST_ID = randomId(); private static final String PRIMARY_REQUEST_ID = SECONDARY_REQUEST_ID; + private static final String INTERMEDIATE_REQUEST_ID = SECONDARY_REQUEST_ID; private static final String UUID_PATTERN = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}"; @@ -113,10 +118,11 @@ public void beforeEach() { "RECALL, false, true, ITEM", "RECALL, false, false, ITEM" }) - void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestRequesterExists, - boolean secondaryRequestPickupServicePointExists, EcsTlr.RequestLevelEnum requestLevel) { + void ecsTlrIsCreated(RequestTypeEnum requestType, boolean requesterClonesExist, + boolean pickupServicePointClonesExist, EcsTlr.RequestLevelEnum requestLevel) { - EcsTlr ecsTlr = buildEcsTlr(requestType, requestLevel); + EcsTlr ecsTlr = buildEcsTlr(requestType, requestLevel) + .primaryRequestTenantId(TENANT_ID_UNIVERSITY); // 1. Create stubs for other modules // 1.1 Mock search endpoint @@ -148,51 +154,54 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques // 1.2 Mock user endpoints User primaryRequestRequester = buildPrimaryRequestRequester(REQUESTER_ID); - User secondaryRequestRequester = buildSecondaryRequestRequester(primaryRequestRequester, - secondaryRequestRequesterExists); + User requesterClone = buildRequesterClone(primaryRequestRequester, + requesterClonesExist); wireMockServer.stubFor(get(urlMatching(USERS_URL + "/" + REQUESTER_ID)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY)) .willReturn(jsonResponse(primaryRequestRequester, HttpStatus.SC_OK))); - ResponseDefinitionBuilder mockGetSecondaryRequesterResponse = secondaryRequestRequesterExists - ? jsonResponse(secondaryRequestRequester, HttpStatus.SC_OK) + ResponseDefinitionBuilder mockGetClonedRequesterResponse = requesterClonesExist + ? jsonResponse(requesterClone, HttpStatus.SC_OK) : notFound(); wireMockServer.stubFor(get(urlMatching(USERS_URL + "/" + REQUESTER_ID)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) - .willReturn(mockGetSecondaryRequesterResponse)); + .withHeader(HEADER_TENANT, WireMock.including(TENANT_ID_COLLEGE)) + .willReturn(mockGetClonedRequesterResponse)); + + wireMockServer.stubFor(get(urlMatching(USERS_URL + "/" + REQUESTER_ID)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) + .willReturn(mockGetClonedRequesterResponse)); wireMockServer.stubFor(post(urlMatching(USERS_URL)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) - .willReturn(jsonResponse(secondaryRequestRequester, HttpStatus.SC_CREATED))); + .withHeader(HEADER_TENANT, not(equalTo(TENANT_ID_UNIVERSITY))) + .willReturn(jsonResponse(requesterClone, HttpStatus.SC_CREATED))); wireMockServer.stubFor(put(urlMatching(USERS_URL + "/" + REQUESTER_ID)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) + .withHeader(HEADER_TENANT, not(equalTo(TENANT_ID_UNIVERSITY))) .willReturn(jsonResponse(primaryRequestRequester, HttpStatus.SC_NO_CONTENT))); // 1.3 Mock service point endpoints ServicePoint primaryRequestPickupServicePoint = buildPrimaryRequestPickupServicePoint(PICKUP_SERVICE_POINT_ID); - ServicePoint secondaryRequestPickupServicePoint = - buildSecondaryRequestPickupServicePoint(primaryRequestPickupServicePoint); + ServicePoint servicePointClone = buildPickupServicePointClone(primaryRequestPickupServicePoint); wireMockServer.stubFor(get(urlMatching(SERVICE_POINTS_URL + "/" + PICKUP_SERVICE_POINT_ID)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY)) .willReturn(jsonResponse(asJsonString(primaryRequestPickupServicePoint), HttpStatus.SC_OK))); - var mockGetSecondaryRequestPickupServicePointResponse = secondaryRequestPickupServicePointExists - ? jsonResponse(asJsonString(secondaryRequestPickupServicePoint), HttpStatus.SC_OK) + var mockGetClonedPickupServicePointResponse = pickupServicePointClonesExist + ? jsonResponse(asJsonString(servicePointClone), HttpStatus.SC_OK) : notFound(); wireMockServer.stubFor(get(urlMatching(SERVICE_POINTS_URL + "/" + PICKUP_SERVICE_POINT_ID)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) - .willReturn(mockGetSecondaryRequestPickupServicePointResponse)); + .withHeader(HEADER_TENANT, not(equalTo(TENANT_ID_UNIVERSITY))) + .willReturn(mockGetClonedPickupServicePointResponse)); wireMockServer.stubFor(post(urlMatching(SERVICE_POINTS_URL)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) - .willReturn(jsonResponse(asJsonString(secondaryRequestPickupServicePoint), HttpStatus.SC_CREATED))); + .withHeader(HEADER_TENANT, not(equalTo(TENANT_ID_UNIVERSITY))) + .willReturn(jsonResponse(asJsonString(servicePointClone), HttpStatus.SC_CREATED))); // 1.4 Mock request endpoints @@ -204,8 +213,11 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques .item(new RequestItem().barcode(ITEM_BARCODE)) .instance(new RequestInstance().title(INSTANCE_TITLE)); - Request primaryRequestPostRequest = buildPrimaryRequest(secondaryRequestPostRequest); - Request mockPostPrimaryRequestResponse = buildPrimaryRequest(mockPostSecondaryRequestResponse); + Request primaryRequestPostRequest = buildRequest(secondaryRequestPostRequest, PRIMARY); + Request mockPostPrimaryRequestResponse = buildRequest(mockPostSecondaryRequestResponse, PRIMARY); + + Request intermediateRequestPostRequest = buildRequest(secondaryRequestPostRequest, INTERMEDIATE); + Request mockPostIntermediateRequestResponse = buildRequest(mockPostSecondaryRequestResponse, INTERMEDIATE); wireMockServer.stubFor(post(urlMatching(REQUESTS_URL)) .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) @@ -213,20 +225,33 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques .willReturn(jsonResponse(asJsonString(mockPostSecondaryRequestResponse), HttpStatus.SC_CREATED))); wireMockServer.stubFor(post(urlMatching(REQUESTS_URL)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY)) .withRequestBody(equalToJson(asJsonString(primaryRequestPostRequest))) .willReturn(jsonResponse(asJsonString(mockPostPrimaryRequestResponse), HttpStatus.SC_CREATED))); + wireMockServer.stubFor(post(urlMatching(REQUESTS_URL)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) + .withRequestBody(equalToJson(asJsonString(intermediateRequestPostRequest))) + .willReturn(jsonResponse(asJsonString(mockPostIntermediateRequestResponse), HttpStatus.SC_CREATED))); + // 1.5 Mock DCB endpoints - DcbTransaction borrowerTransactionPostRequest = new DcbTransaction() - .role(DcbTransaction.RoleEnum.BORROWING_PICKUP) + DcbTransaction pickupTransactionPostRequest = new DcbTransaction() + .role(DcbTransaction.RoleEnum.PICKUP) .item(new DcbItem() .id(ITEM_ID) .barcode(ITEM_BARCODE) .title(INSTANCE_TITLE)) .requestId(PRIMARY_REQUEST_ID); + DcbTransaction borrowerTransactionPostRequest = new DcbTransaction() + .role(DcbTransaction.RoleEnum.BORROWER) + .item(new DcbItem() + .id(ITEM_ID) + .barcode(ITEM_BARCODE) + .title(INSTANCE_TITLE)) + .requestId(INTERMEDIATE_REQUEST_ID); + DcbTransaction lenderTransactionPostRequest = new DcbTransaction() .role(DcbTransaction.RoleEnum.LENDER) .requestId(SECONDARY_REQUEST_ID); @@ -234,6 +259,11 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques TransactionStatusResponse mockPostEcsDcbTransactionResponse = new TransactionStatusResponse() .status(TransactionStatusResponse.StatusEnum.CREATED); + wireMockServer.stubFor(post(urlMatching(POST_ECS_REQUEST_TRANSACTION_URL_PATTERN)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY)) + .withRequestBody(equalToJson(asJsonString(pickupTransactionPostRequest))) + .willReturn(jsonResponse(mockPostEcsDcbTransactionResponse, HttpStatus.SC_CREATED))); + wireMockServer.stubFor(post(urlMatching(POST_ECS_REQUEST_TRANSACTION_URL_PATTERN)) .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) .withRequestBody(equalToJson(asJsonString(borrowerTransactionPostRequest))) @@ -244,6 +274,8 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques .withRequestBody(equalToJson(asJsonString(lenderTransactionPostRequest))) .willReturn(jsonResponse(mockPostEcsDcbTransactionResponse, HttpStatus.SC_CREATED))); + // 1.6 Mock circulation item endpoints + wireMockServer.stubFor(get(urlMatching("/circulation-item/" + ITEM_ID)) .willReturn(notFound())); @@ -279,9 +311,11 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques EcsTlr expectedPostEcsTlrResponse = buildEcsTlr(requestType, requestLevel) .primaryRequestId(PRIMARY_REQUEST_ID) - .primaryRequestTenantId(TENANT_ID_CONSORTIUM) + .primaryRequestTenantId(TENANT_ID_UNIVERSITY) .secondaryRequestId(SECONDARY_REQUEST_ID) .secondaryRequestTenantId(TENANT_ID_COLLEGE) + .intermediateRequestId(INTERMEDIATE_REQUEST_ID) + .intermediateRequestTenantId(TENANT_ID_CONSORTIUM) .itemId(requestType == HOLD ? null : ITEM_ID); assertEquals(TENANT_ID_CONSORTIUM, getCurrentTenantId()); @@ -320,23 +354,26 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean secondaryRequestReques wireMockServer.verify(postRequestedFor(urlMatching(REQUESTS_URL)) .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) - .withRequestBody(equalToJson(asJsonString(primaryRequestPostRequest)))); + .withRequestBody(equalToJson(asJsonString(intermediateRequestPostRequest)))); - if (secondaryRequestRequesterExists) { + if (requesterClonesExist) { wireMockServer.verify(exactly(0), postRequestedFor(urlMatching(USERS_URL))); - wireMockServer.verify(exactly(1), putRequestedFor(urlMatching(USERS_URL + "/" + REQUESTER_ID))); + wireMockServer.verify(exactly(2), putRequestedFor(urlMatching(USERS_URL + "/" + REQUESTER_ID))); } else { wireMockServer.verify(postRequestedFor(urlMatching(USERS_URL)) .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) - .withRequestBody(equalToJson(asJsonString(secondaryRequestRequester)))); + .withRequestBody(equalToJson(asJsonString(requesterClone)))); } - if (secondaryRequestPickupServicePointExists) { + if (pickupServicePointClonesExist) { wireMockServer.verify(exactly(0), postRequestedFor(urlMatching(SERVICE_POINTS_URL))); } else { wireMockServer.verify(postRequestedFor(urlMatching(SERVICE_POINTS_URL)) .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) - .withRequestBody(equalToJson(asJsonString(secondaryRequestPickupServicePoint)))); + .withRequestBody(equalToJson(asJsonString(servicePointClone)))); + wireMockServer.verify(postRequestedFor(urlMatching(SERVICE_POINTS_URL)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) + .withRequestBody(equalToJson(asJsonString(servicePointClone)))); } wireMockServer.verify(postRequestedFor(urlMatching(POST_ECS_REQUEST_TRANSACTION_URL_PATTERN)) @@ -481,7 +518,9 @@ private static Request buildSecondaryRequest(EcsTlr ecsTlr) { .patronComments(ecsTlr.getPatronComments()); } - private static Request buildPrimaryRequest(Request secondaryRequest) { + private static Request buildRequest(Request secondaryRequest, + Request.EcsRequestPhaseEnum ecsRequestPhase) { + return new Request() .id(PRIMARY_REQUEST_ID) .itemId(ITEM_ID) @@ -493,7 +532,7 @@ private static Request buildPrimaryRequest(Request secondaryRequest) { .requestDate(secondaryRequest.getRequestDate()) .requestLevel(secondaryRequest.getRequestLevel()) .requestType(secondaryRequest.getRequestType()) - .ecsRequestPhase(Request.EcsRequestPhaseEnum.PRIMARY) + .ecsRequestPhase(ecsRequestPhase) .fulfillmentPreference(secondaryRequest.getFulfillmentPreference()) .pickupServicePointId(secondaryRequest.getPickupServicePointId()); } @@ -520,7 +559,7 @@ private static User buildPrimaryRequestRequester(String userId) { .customFields(null); } - private static User buildSecondaryRequestRequester(User primaryRequestRequester, + private static User buildRequesterClone(User primaryRequestRequester, boolean secondaryRequestRequesterExists) { return new User() @@ -542,7 +581,7 @@ private static ServicePoint buildPrimaryRequestPickupServicePoint(String id) { .pickupLocation(true); } - private static ServicePoint buildSecondaryRequestPickupServicePoint( + private static ServicePoint buildPickupServicePointClone( ServicePoint primaryRequestPickupServicePoint) { return new ServicePoint() From 1dbf8666bb8a96deaf271ab928bdf87774c451d0 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Mon, 9 Dec 2024 18:07:36 +0200 Subject: [PATCH 29/30] MODTLR-98 Extend integration test --- src/test/java/org/folio/api/EcsTlrApiTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/folio/api/EcsTlrApiTest.java b/src/test/java/org/folio/api/EcsTlrApiTest.java index 29abcb63..29bc46c9 100644 --- a/src/test/java/org/folio/api/EcsTlrApiTest.java +++ b/src/test/java/org/folio/api/EcsTlrApiTest.java @@ -349,13 +349,17 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean requesterClonesExist, .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))); wireMockServer.verify(postRequestedFor(urlMatching(REQUESTS_URL)) - .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) // because this tenant has available item + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) .withRequestBody(equalToJson(asJsonString(secondaryRequestPostRequest)))); wireMockServer.verify(postRequestedFor(urlMatching(REQUESTS_URL)) .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM)) .withRequestBody(equalToJson(asJsonString(intermediateRequestPostRequest)))); + wireMockServer.verify(postRequestedFor(urlMatching(REQUESTS_URL)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY)) + .withRequestBody(equalToJson(asJsonString(primaryRequestPostRequest)))); + if (requesterClonesExist) { wireMockServer.verify(exactly(0), postRequestedFor(urlMatching(USERS_URL))); wireMockServer.verify(exactly(2), putRequestedFor(urlMatching(USERS_URL + "/" + REQUESTER_ID))); @@ -383,6 +387,10 @@ void ecsTlrIsCreated(RequestTypeEnum requestType, boolean requesterClonesExist, wireMockServer.verify(postRequestedFor(urlMatching(POST_ECS_REQUEST_TRANSACTION_URL_PATTERN)) .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE)) .withRequestBody(equalToJson(asJsonString(lenderTransactionPostRequest)))); + + wireMockServer.verify(postRequestedFor(urlMatching(POST_ECS_REQUEST_TRANSACTION_URL_PATTERN)) + .withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY)) + .withRequestBody(equalToJson(asJsonString(pickupTransactionPostRequest)))); } @Test From 43252dd0bdae40684d0fdb226de31c3e515b49f2 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Mon, 9 Dec 2024 18:23:16 +0200 Subject: [PATCH 30/30] MODTLR-98 Fix code smells --- src/main/java/org/folio/service/impl/RequestServiceImpl.java | 2 -- src/test/java/org/folio/service/RequestServiceTest.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java index b876d286..313d4b8e 100644 --- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java +++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java @@ -139,7 +139,6 @@ public RequestWrapper createIntermediateRequest(Request intermediateRequest, final String requesterId = intermediateRequest.getRequesterId(); final String pickupServicePointId = intermediateRequest.getPickupServicePointId(); - // TODO: fetch both in one call to system user User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId, () -> userService.find(requesterId)); ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped( @@ -210,7 +209,6 @@ public CirculationItem createCirculationItem(Request request, String inventoryTe return existingCirculationItem; } - // TODO: fetch both in one system user call InventoryItem item = getItemFromStorage(itemId, inventoryTenantId); InventoryInstance instance = getInstanceFromStorage(instanceId, inventoryTenantId); diff --git a/src/test/java/org/folio/service/RequestServiceTest.java b/src/test/java/org/folio/service/RequestServiceTest.java index 05905021..b0261431 100644 --- a/src/test/java/org/folio/service/RequestServiceTest.java +++ b/src/test/java/org/folio/service/RequestServiceTest.java @@ -39,7 +39,6 @@ class RequestServiceTest { private Request secondaryRequest; private static final String ITEM_ID = UUID.randomUUID().toString(); private static final String INSTANCE_ID = UUID.randomUUID().toString(); - private static final String BORROWER_ID = UUID.randomUUID().toString(); private static final String LENDER_ID = UUID.randomUUID().toString(); private static final String HOLDINGS_RECORD_ID = "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9"; private static final String LENDING_LIBRARY_CODE = "TEST_CODE";