diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json
index a98053c7..a5ec2216 100644
--- a/descriptors/ModuleDescriptor-template.json
+++ b/descriptors/ModuleDescriptor-template.json
@@ -46,6 +46,32 @@
}
]
},
+ {
+ "id": "ecs-request-external",
+ "version": "1.0",
+ "handlers": [
+ {
+ "methods": ["POST"],
+ "pathPattern": "/tlr/create-ecs-request-external",
+ "permissionsRequired": ["tlr.ecs-request-external.post"],
+ "modulePermissions": [
+ "circulation.requests.instances.item.post",
+ "circulation.requests.item.post",
+ "circulation-item.item.get",
+ "circulation-item.collection.get",
+ "circulation-item.item.post",
+ "circulation-item.item.put",
+ "search.instances.collection.get",
+ "users.item.get",
+ "users.collection.get",
+ "users.item.post",
+ "inventory-storage.service-points.item.get",
+ "inventory-storage.service-points.collection.get",
+ "inventory-storage.service-points.item.post"
+ ]
+ }
+ ]
+ },
{
"id": "ecs-tlr-allowed-service-points",
"version": "1.0",
@@ -205,6 +231,11 @@
"permissionName": "tlr.staff-slips.pick-slips.get",
"displayName": "ecs-tlr - pick slips",
"description": "Get pick slips"
+ },
+ {
+ "permissionName": "tlr.ecs-request-external.post",
+ "displayName": "ecs-request-external - create ECS request external",
+ "description": "Create ECS request external"
}
],
"requires": [
diff --git a/pom.xml b/pom.xml
index 69e72198..191faebb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -405,6 +405,33 @@
+
+ ecs-request-external
+
+ generate
+
+
+ ${project.basedir}/src/main/resources/swagger.api/ecs-request-external.yaml
+
+ spring
+ ${project.groupId}.domain.dto
+ ${project.groupId}.rest.resource
+ true
+ true
+ true
+ true
+ false
+ true
+ ApiUtil.java
+ true
+
+ java
+ true
+ true
+ true
+
+
+
diff --git a/src/main/java/org/folio/client/feign/CirculationClient.java b/src/main/java/org/folio/client/feign/CirculationClient.java
index 061596b4..3afd10d2 100644
--- a/src/main/java/org/folio/client/feign/CirculationClient.java
+++ b/src/main/java/org/folio/client/feign/CirculationClient.java
@@ -18,30 +18,19 @@ public interface CirculationClient {
Request createRequest(Request request);
@GetMapping("/requests/allowed-service-points")
- AllowedServicePointsResponse allowedServicePointsWithStubItem(
- @RequestParam("patronGroupId") String patronGroupId, @RequestParam("instanceId") String instanceId,
- @RequestParam("operation") String operation, @RequestParam("useStubItem") boolean useStubItem);
-
- @GetMapping("/requests/allowed-service-points")
- AllowedServicePointsResponse allowedServicePointsWithStubItem(
- @RequestParam("operation") String operation, @RequestParam("requestId") String requestId,
- @RequestParam("useStubItem") boolean useStubItem);
-
- @GetMapping("/requests/allowed-service-points")
- AllowedServicePointsResponse allowedRoutingServicePoints(
- @RequestParam("patronGroupId") String patronGroupId, @RequestParam("instanceId") String instanceId,
+ AllowedServicePointsResponse allowedServicePointsByInstance(
+ @RequestParam("patronGroupId") String patronGroupId,
@RequestParam("operation") String operation,
- @RequestParam("ecsRequestRouting") boolean ecsRequestRouting);
+ @RequestParam("instanceId") String instanceId);
@GetMapping("/requests/allowed-service-points")
- AllowedServicePointsResponse allowedRoutingServicePoints(
- @RequestParam("operation") String operation, @RequestParam("requestId") String requestId,
- @RequestParam("ecsRequestRouting") boolean ecsRequestRouting);
-
- @GetMapping("/requests/allowed-service-points")
- AllowedServicePointsResponse allowedRoutingServicePoints(
+ AllowedServicePointsResponse allowedServicePointsByItem(
@RequestParam("patronGroupId") String patronGroupId,
@RequestParam("operation") String operation,
- @RequestParam("ecsRequestRouting") boolean ecsRequestRouting,
@RequestParam("itemId") String itemId);
+
+ @GetMapping("/requests/allowed-service-points")
+ AllowedServicePointsResponse allowedServicePoints(
+ @RequestParam("operation") String operation,
+ @RequestParam("requestId") String requestId);
}
diff --git a/src/main/java/org/folio/controller/AllowedServicePointsController.java b/src/main/java/org/folio/controller/AllowedServicePointsController.java
index d7e9750d..bcdb027c 100644
--- a/src/main/java/org/folio/controller/AllowedServicePointsController.java
+++ b/src/main/java/org/folio/controller/AllowedServicePointsController.java
@@ -5,8 +5,6 @@
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
-import java.util.ArrayList;
-import java.util.List;
import java.util.UUID;
import org.folio.domain.dto.AllowedServicePointsRequest;
@@ -38,20 +36,15 @@ public ResponseEntity getAllowedServicePoints(Stri
AllowedServicePointsRequest request = new AllowedServicePointsRequest(
operation, requesterId, instanceId, requestId, itemId);
- if (validateAllowedServicePointsRequest(request)) {
- var allowedServicePointsService = getAllowedServicePointsService(request);
- var response = allowedServicePointsService.getAllowedServicePoints(request);
- return ResponseEntity.status(OK).body(response);
- } else {
+ if (!validateAllowedServicePointsRequest(request)) {
return ResponseEntity.status(UNPROCESSABLE_ENTITY).build();
}
- }
-
- private AllowedServicePointsService getAllowedServicePointsService(
- AllowedServicePointsRequest request) {
- return request.isForTitleLevelRequest()
+ var allowedServicePointsService = request.isForTitleLevelRequest()
? allowedServicePointsForTitleLevelRequestService
: allowedServicePointsForItemLevelRequestService;
+
+ return ResponseEntity.status(OK).body(allowedServicePointsService
+ .getAllowedServicePoints(request));
}
private static boolean validateAllowedServicePointsRequest(AllowedServicePointsRequest request) {
@@ -63,8 +56,6 @@ private static boolean validateAllowedServicePointsRequest(AllowedServicePointsR
boolean allowedCombinationOfParametersDetected = false;
- List errors = new ArrayList<>();
-
if (operation == CREATE && requesterId != null && instanceId != null &&
itemId == null && requestId == null) {
@@ -87,13 +78,8 @@ private static boolean validateAllowedServicePointsRequest(AllowedServicePointsR
}
if (!allowedCombinationOfParametersDetected) {
- String errorMessage = "Invalid combination of query parameters";
- errors.add(errorMessage);
- }
-
- if (!errors.isEmpty()) {
- String errorMessage = String.join(" ", errors);
- log.error("validateRequest:: allowed service points request failed: {}", errorMessage);
+ log.error("validateRequest:: allowed service points request failed: " +
+ "Invalid combination of query parameters");
return false;
}
diff --git a/src/main/java/org/folio/controller/EcsRequestExternalController.java b/src/main/java/org/folio/controller/EcsRequestExternalController.java
new file mode 100644
index 00000000..e71cbd31
--- /dev/null
+++ b/src/main/java/org/folio/controller/EcsRequestExternalController.java
@@ -0,0 +1,60 @@
+package org.folio.controller;
+
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.CREATED;
+
+import org.folio.domain.dto.EcsRequestExternal;
+import org.folio.domain.dto.EcsTlr;
+import org.folio.domain.mapper.ExternalEcsRequestMapper;
+import org.folio.exception.RequestCreatingException;
+import org.folio.rest.resource.EcsRequestExternalApi;
+import org.folio.service.EcsTlrService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
+@RestController
+@Log4j2
+@AllArgsConstructor
+public class EcsRequestExternalController implements EcsRequestExternalApi {
+
+ private static final EcsTlr.RequestTypeEnum[] ORDERED_REQUEST_TYPES = {
+ EcsTlr.RequestTypeEnum.PAGE,
+ EcsTlr.RequestTypeEnum.RECALL,
+ EcsTlr.RequestTypeEnum.HOLD
+ };
+
+ private final EcsTlrService ecsTlrService;
+ private final ExternalEcsRequestMapper externalEcsRequestMapper;
+
+ @Override
+ public ResponseEntity postEcsRequestExternal(EcsRequestExternal ecsRequestExternal) {
+ log.info("postEcsRequestExternal:: creating external ECS request, instance {}, " +
+ "item {}, requester {}", ecsRequestExternal.getInstanceId(),
+ ecsRequestExternal.getItemId(), ecsRequestExternal.getRequesterId());
+
+ EcsTlr ecsTlrDto = externalEcsRequestMapper.mapEcsRequestExternalToEcsTlr(ecsRequestExternal);
+
+ for (EcsTlr.RequestTypeEnum requestType: ORDERED_REQUEST_TYPES) {
+ EcsTlr ecsTlr;
+ try {
+ ecsTlr = ecsTlrService.create(ecsTlrDto.requestType(requestType));
+ } catch (RequestCreatingException e) {
+ log.warn("postEcsRequestExternal:: failed to create ECS request, message: {}, cause: {}",
+ e.getMessage(), e.getCause());
+ ecsTlr = null;
+ }
+
+ if (ecsTlr != null) {
+ log.info("postEcsRequestExternal:: created ECS request {}, request type is {}",
+ ecsTlr.getId(), requestType);
+ return ResponseEntity.status(CREATED).body(ecsTlr);
+ }
+ }
+
+ log.warn("postEcsRequestExternal:: failed to create external ECS request");
+ return ResponseEntity.status(BAD_REQUEST).build();
+ }
+}
diff --git a/src/main/java/org/folio/domain/mapper/ExternalEcsRequestMapper.java b/src/main/java/org/folio/domain/mapper/ExternalEcsRequestMapper.java
new file mode 100644
index 00000000..70486877
--- /dev/null
+++ b/src/main/java/org/folio/domain/mapper/ExternalEcsRequestMapper.java
@@ -0,0 +1,34 @@
+package org.folio.domain.mapper;
+
+import org.folio.domain.dto.EcsRequestExternal;
+import org.folio.domain.dto.EcsTlr;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Named;
+import org.mapstruct.NullValueCheckStrategy;
+
+@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
+public interface ExternalEcsRequestMapper {
+
+ @Mapping(target = "requestLevel", qualifiedByName = "ExternalEcsRequestToEcsTlrRequestLevel")
+ @Mapping(target = "fulfillmentPreference", qualifiedByName = "ExternalEcsRequestToEcsTlrFulfillmentPreference")
+ EcsTlr mapEcsRequestExternalToEcsTlr(EcsRequestExternal ecsRequestExternal);
+
+ @Named("ExternalEcsRequestToEcsTlrRequestLevel")
+ default EcsTlr.RequestLevelEnum mapExternalEcsRequestToEcsTlrRequestLevel(
+ EcsRequestExternal.RequestLevelEnum ecsRequestExternalRequestLevel) {
+
+ return ecsRequestExternalRequestLevel != null
+ ? EcsTlr.RequestLevelEnum.fromValue(ecsRequestExternalRequestLevel.getValue())
+ : null;
+ }
+
+ @Named("ExternalEcsRequestToEcsTlrFulfillmentPreference")
+ default EcsTlr.FulfillmentPreferenceEnum mapExternalEcsRequestToEcsTlrFulfillmentPreference(
+ EcsRequestExternal.FulfillmentPreferenceEnum fulfillmentPreference) {
+ return fulfillmentPreference != null
+ ? EcsTlr.FulfillmentPreferenceEnum.fromValue(fulfillmentPreference.getValue())
+ : null;
+ }
+
+}
diff --git a/src/main/java/org/folio/service/impl/AllowedServicePointsForItemLevelRequestService.java b/src/main/java/org/folio/service/impl/AllowedServicePointsForItemLevelRequestService.java
index 1e9ac8e1..4e11b8e7 100644
--- a/src/main/java/org/folio/service/impl/AllowedServicePointsForItemLevelRequestService.java
+++ b/src/main/java/org/folio/service/impl/AllowedServicePointsForItemLevelRequestService.java
@@ -41,15 +41,15 @@ protected Collection getLendingTenants(AllowedServicePointsRequest reque
}
@Override
- protected AllowedServicePointsResponse getAllowedServicePointsFromLendingTenant(
+ protected AllowedServicePointsResponse getAllowedServicePointsFromTenant(
AllowedServicePointsRequest request, String patronGroupId, String tenantId) {
- log.info("getAllowedServicePointsFromLendingTenant:: parameters: request: {}, " +
+ log.info("getAllowedServicePointsFromTenant:: parameters: request: {}, " +
"patronGroupId: {}, tenantId: {}", request, patronGroupId, tenantId);
return executionService.executeSystemUserScoped(tenantId,
- () -> circulationClient.allowedRoutingServicePoints(patronGroupId,
- request.getOperation().getValue(), true, request.getItemId()));
+ () -> circulationClient.allowedServicePointsByItem(patronGroupId,
+ request.getOperation().getValue(), request.getItemId()));
}
}
diff --git a/src/main/java/org/folio/service/impl/AllowedServicePointsForTitleLevelRequestService.java b/src/main/java/org/folio/service/impl/AllowedServicePointsForTitleLevelRequestService.java
index a219e067..4313d18c 100644
--- a/src/main/java/org/folio/service/impl/AllowedServicePointsForTitleLevelRequestService.java
+++ b/src/main/java/org/folio/service/impl/AllowedServicePointsForTitleLevelRequestService.java
@@ -48,12 +48,12 @@ protected Collection getLendingTenants(AllowedServicePointsRequest reque
}
@Override
- protected AllowedServicePointsResponse getAllowedServicePointsFromLendingTenant(
+ protected AllowedServicePointsResponse getAllowedServicePointsFromTenant(
AllowedServicePointsRequest request, String patronGroupId, String tenantId) {
return executionService.executeSystemUserScoped(tenantId,
- () -> circulationClient.allowedRoutingServicePoints(patronGroupId, request.getInstanceId(),
- request.getOperation().getValue(), true));
+ () -> circulationClient.allowedServicePointsByInstance(patronGroupId,
+ request.getOperation().getValue(), request.getInstanceId()));
}
}
diff --git a/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java b/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java
index c50f1b89..1aa0d983 100644
--- a/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java
+++ b/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java
@@ -3,13 +3,15 @@
import static org.folio.domain.dto.RequestOperation.REPLACE;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.UUID;
-import java.util.stream.Stream;
import org.folio.client.feign.CirculationClient;
import org.folio.client.feign.SearchClient;
-import org.folio.domain.Constants;
+import org.folio.domain.dto.AllowedServicePointsInner;
import org.folio.domain.dto.AllowedServicePointsRequest;
import org.folio.domain.dto.AllowedServicePointsResponse;
import org.folio.domain.dto.Request;
@@ -20,6 +22,7 @@
import org.folio.service.UserService;
import org.folio.spring.service.SystemUserScopedExecutionService;
import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
@@ -49,58 +52,62 @@ private AllowedServicePointsResponse getForCreate(AllowedServicePointsRequest re
String patronGroupId = userService.find(request.getRequesterId()).getPatronGroup();
log.info("getForCreate:: patronGroupId={}", patronGroupId);
- boolean isAvailableInLendingTenants = getLendingTenants(request)
- .stream()
- .anyMatch(tenant -> isAvailableInLendingTenant(request, patronGroupId, tenant));
+ Map page = new HashMap<>();
+ Map hold = new HashMap<>();
+ Map recall = new HashMap<>();
+ for (String tenantId : getLendingTenants(request)) {
+ var servicePoints = getAllowedServicePointsFromTenant(request, patronGroupId, tenantId);
+ log.info("getForCreate:: service points from {}: {}", tenantId, servicePoints);
- if (!isAvailableInLendingTenants) {
- log.info("getForCreate:: Not available for requesting, returning empty result");
- return new AllowedServicePointsResponse();
+ combineAndFilterDuplicates(page, servicePoints.getPage());
+ combineAndFilterDuplicates(hold, servicePoints.getHold());
+ combineAndFilterDuplicates(recall, servicePoints.getRecall());
}
- log.info("getForCreate:: Available for requesting, proxying call");
- return circulationClient.allowedServicePointsWithStubItem(patronGroupId, request.getInstanceId(),
- request.getOperation().getValue(), true);
+ return new AllowedServicePointsResponse()
+ .page(Set.copyOf(page.values()))
+ .hold(Set.copyOf(hold.values()))
+ .recall(Set.copyOf(recall.values()));
}
- protected abstract Collection getLendingTenants(AllowedServicePointsRequest request);
-
- private boolean isAvailableInLendingTenant(AllowedServicePointsRequest request, String patronGroupId,
- String tenantId) {
-
- var allowedServicePointsResponse = getAllowedServicePointsFromLendingTenant(request,
- patronGroupId, tenantId);
- log.info("isAvailableInLendingTenant:: allowedServicePointsResponse: {}",
- allowedServicePointsResponse);
+ private void combineAndFilterDuplicates(
+ Map servicePoints, Set toAdd) {
- var availabilityCheckResult = Stream.of(allowedServicePointsResponse.getHold(),
- allowedServicePointsResponse.getPage(), allowedServicePointsResponse.getRecall())
+ if (CollectionUtils.isEmpty(toAdd)) {
+ return;
+ }
+ toAdd.stream()
.filter(Objects::nonNull)
- .flatMap(Collection::stream)
- .anyMatch(Objects::nonNull);
-
- log.info("isAvailableInLendingTenant:: result: {}", availabilityCheckResult);
- return availabilityCheckResult;
+ .forEach(allowedSp -> servicePoints.put(allowedSp.getId(), allowedSp));
}
- protected abstract AllowedServicePointsResponse getAllowedServicePointsFromLendingTenant(
+ protected abstract Collection getLendingTenants(AllowedServicePointsRequest request);
+
+ protected abstract AllowedServicePointsResponse getAllowedServicePointsFromTenant(
AllowedServicePointsRequest request, String patronGroupId, String tenantId);
private AllowedServicePointsResponse getForReplace(AllowedServicePointsRequest request) {
EcsTlrEntity ecsTlr = findEcsTlr(request);
- final boolean requestIsLinkedToItem = ecsTlr.getItemId() != null;
- log.info("getForReplace:: request is linked to an item: {}", requestIsLinkedToItem);
- if (!requestIsLinkedToItem && isRequestingNotAllowedInLendingTenant(ecsTlr)) {
- log.info("getForReplace:: no service points are allowed in lending tenant");
- return new AllowedServicePointsResponse();
- }
+ log.info("getForReplace:: fetching allowed service points from secondary request tenant");
+ var allowedServicePoints = executionService.executeSystemUserScoped(
+ ecsTlr.getSecondaryRequestTenantId(), () -> circulationClient.allowedServicePoints(
+ REPLACE.getValue(), ecsTlr.getSecondaryRequestId().toString()));
+
+ Request secondaryRequest = requestService.getRequestFromStorage(
+ ecsTlr.getSecondaryRequestId().toString(), ecsTlr.getSecondaryRequestTenantId());
+ Request.RequestTypeEnum secondaryRequestType = secondaryRequest.getRequestType();
+ log.info("getForReplace:: secondary request type: {}", secondaryRequestType.getValue());
- return getAllowedServicePointsFromBorrowingTenant(request);
+ return switch (secondaryRequestType) {
+ case PAGE -> new AllowedServicePointsResponse().page(allowedServicePoints.getPage());
+ case HOLD -> new AllowedServicePointsResponse().hold(allowedServicePoints.getHold());
+ case RECALL -> new AllowedServicePointsResponse().recall(allowedServicePoints.getRecall());
+ };
}
private EcsTlrEntity findEcsTlr(AllowedServicePointsRequest request) {
- final String primaryRequestId = request.getRequestId();
+ String primaryRequestId = request.getRequestId();
log.info("findEcsTlr:: looking for ECS TLR with primary request {}", primaryRequestId);
EcsTlrEntity ecsTlr = ecsTlrRepository.findByPrimaryRequestId(UUID.fromString(primaryRequestId))
.orElseThrow(() -> new EntityNotFoundException(String.format(
@@ -110,46 +117,4 @@ private EcsTlrEntity findEcsTlr(AllowedServicePointsRequest request) {
return ecsTlr;
}
- private AllowedServicePointsResponse getAllowedServicePointsFromBorrowingTenant(
- AllowedServicePointsRequest request) {
-
- log.info("getForReplace:: fetching allowed service points from borrowing tenant");
- var allowedServicePoints = circulationClient.allowedServicePointsWithStubItem(
- REPLACE.getValue(), request.getRequestId(), true);
-
- Request.RequestTypeEnum primaryRequestType = Constants.PRIMARY_REQUEST_TYPE;
- log.info("getAllowedServicePointsFromBorrowingTenant:: primary request type: {}",
- primaryRequestType.getValue());
-
- return switch (primaryRequestType) {
- case PAGE -> new AllowedServicePointsResponse().page(allowedServicePoints.getPage());
- case HOLD -> new AllowedServicePointsResponse().hold(allowedServicePoints.getHold());
- case RECALL -> new AllowedServicePointsResponse().recall(allowedServicePoints.getRecall());
- };
- }
-
- private boolean isRequestingNotAllowedInLendingTenant(EcsTlrEntity ecsTlr) {
- log.info("isRequestingNotAllowedInLendingTenant:: checking if requesting is allowed in lending tenant");
- var allowedServicePointsInLendingTenant = executionService.executeSystemUserScoped(
- ecsTlr.getSecondaryRequestTenantId(), () -> circulationClient.allowedRoutingServicePoints(
- REPLACE.getValue(), ecsTlr.getSecondaryRequestId().toString(), true));
-
- Request secondaryRequest = requestService.getRequestFromStorage(
- ecsTlr.getSecondaryRequestId().toString(), ecsTlr.getSecondaryRequestTenantId());
- Request.RequestTypeEnum secondaryRequestType = secondaryRequest.getRequestType();
- log.info("isRequestingNotAllowedInLendingTenant:: secondary request type: {}",
- secondaryRequestType.getValue());
-
- var allowedServicePointsForRequestType = switch (secondaryRequestType) {
- case PAGE -> allowedServicePointsInLendingTenant.getPage();
- case HOLD -> allowedServicePointsInLendingTenant.getHold();
- case RECALL -> allowedServicePointsInLendingTenant.getRecall();
- };
-
- log.debug("isRequestingNotAllowedInLendingTenant:: allowed service points for {}: {}",
- secondaryRequestType.getValue(), allowedServicePointsForRequestType);
-
- return allowedServicePointsForRequestType == null || allowedServicePointsForRequestType.isEmpty();
- }
-
}
diff --git a/src/main/resources/swagger.api/ecs-request-external.yaml b/src/main/resources/swagger.api/ecs-request-external.yaml
new file mode 100644
index 00000000..bda0f34b
--- /dev/null
+++ b/src/main/resources/swagger.api/ecs-request-external.yaml
@@ -0,0 +1,59 @@
+openapi: 3.0.0
+info:
+ title: ECS Request External API
+ version: v1
+tags:
+ - name: ecsRequestExternal
+paths:
+ /tlr/create-ecs-request-external:
+ post:
+ description: Create ECS request external
+ operationId: postEcsRequestExternal
+ tags:
+ - ecsRequestExternal
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ecs-request-external"
+ required: true
+ responses:
+ '201':
+ $ref: "#/components/responses/ecs-tlr"
+ '400':
+ $ref: '#/components/responses/badRequestResponse'
+ '500':
+ $ref: '#/components/responses/internalServerErrorResponse'
+components:
+ schemas:
+ ecs-request-external:
+ $ref: 'schemas/EcsRequestExternal.yaml#/EcsRequestExternal'
+ errorResponse:
+ $ref: 'schemas/errors.json'
+ responses:
+ ecs-tlr:
+ description: ECS TLR object
+ content:
+ application/json:
+ schema:
+ $ref: 'schemas/EcsTlr.yaml#/EcsTlr'
+ badRequestResponse:
+ description: Validation errors
+ content:
+ application/json:
+ example:
+ errors:
+ - message: Request is invalid
+ total_records: 1
+ schema:
+ $ref: "#/components/schemas/errorResponse"
+ internalServerErrorResponse:
+ description: When unhandled exception occurred during code execution, e.g. NullPointerException
+ content:
+ application/json:
+ example:
+ errors:
+ - message: Unexpected error
+ total_records: 1
+ schema:
+ $ref: "#/components/schemas/errorResponse"
diff --git a/src/main/resources/swagger.api/schemas/EcsRequestExternal.yaml b/src/main/resources/swagger.api/schemas/EcsRequestExternal.yaml
new file mode 100644
index 00000000..bd785659
--- /dev/null
+++ b/src/main/resources/swagger.api/schemas/EcsRequestExternal.yaml
@@ -0,0 +1,66 @@
+EcsRequestExternal:
+ description: ECS Request External - title level requests in a multi-tenant environment with Сonsortia support enabled
+ type: "object"
+ properties:
+ id:
+ description: "ID of the ECS TLR"
+ $ref: "uuid.yaml"
+ instanceId:
+ description: "ID of the instance being requested"
+ $ref: "uuid.yaml"
+ requesterId:
+ description: "ID of the requesting patron (user)"
+ $ref: "uuid.yaml"
+ requestLevel:
+ description: "Level of the request - Item or Title"
+ type: string
+ enum: [ "Item", "Title" ]
+ requestExpirationDate:
+ description: "Date when the request expires"
+ type: string
+ format: date-time
+ requestDate:
+ description: "Date when the request was placed"
+ type: string
+ format: date-time
+ patronComments:
+ description: "Comments made by the patron"
+ type: string
+ 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)"
+ type: string
+ enum: ["Hold Shelf", "Delivery"]
+ pickupServicePointId:
+ description: "The ID of the Service Point where this request can be picked up"
+ $ref: "uuid.yaml"
+ itemId:
+ description: "ID of the item being requested"
+ $ref: "uuid.yaml"
+ holdingsRecordId:
+ description: "ID of the holdings record being requested"
+ $ref: "uuid.yaml"
+ primaryRequestId:
+ description: "Primary request ID"
+ $ref: "uuid.yaml"
+ primaryRequestDcbTransactionId:
+ description: "ID of DCB transaction created for primary request"
+ $ref: "uuid.yaml"
+ primaryRequestTenantId:
+ description: "ID of the tenant primary request was created in"
+ type: string
+ secondaryRequestId:
+ description: "Secondary request ID"
+ $ref: "uuid.yaml"
+ secondaryRequestDcbTransactionId:
+ description: "ID of DCB transaction created for secondary request"
+ $ref: "uuid.yaml"
+ secondaryRequestTenantId:
+ description: "ID of the tenant secondary request was created in"
+ type: string
+
+ required:
+ - instanceId
+ - requesterId
+ - requestLevel
+ - fulfillmentPreference
+ - requestDate
diff --git a/src/test/java/org/folio/api/AllowedServicePointsApiTest.java b/src/test/java/org/folio/api/AllowedServicePointsApiTest.java
index d498d7fd..d468fe2c 100644
--- a/src/test/java/org/folio/api/AllowedServicePointsApiTest.java
+++ b/src/test/java/org/folio/api/AllowedServicePointsApiTest.java
@@ -7,8 +7,6 @@
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
import static java.lang.String.format;
import static org.apache.http.HttpStatus.SC_OK;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
import java.util.List;
import java.util.Set;
@@ -26,6 +24,8 @@
import org.folio.repository.EcsTlrRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.beans.factory.annotation.Autowired;
class AllowedServicePointsApiTest extends BaseIT {
@@ -43,7 +43,7 @@ class AllowedServicePointsApiTest extends BaseIT {
ALLOWED_SERVICE_POINTS_URL + "?operation=replace&requestId=" + PRIMARY_REQUEST_ID;
private static final String ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL =
"/circulation/requests/allowed-service-points";
- private static final String ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN =
+ private static final String ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN =
ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL + ".*";
private static final String SEARCH_INSTANCES_URL = "/search/instances.*";
private static final String USER_URL = "/users/" + REQUESTER_ID;
@@ -60,13 +60,21 @@ public void beforeEach() {
}
@Test
- void allowedServicePointReturnsEmptyResultWhenNoRoutingSpInResponsesFromDataTenants() {
- var item1 = new SearchItem();
- item1.setTenantId(TENANT_ID_UNIVERSITY);
+ void allowedServicePointsShouldReturn422WhenParametersAreInvalid() {
+ doGet(ALLOWED_SERVICE_POINTS_URL + format("?operation=create&requesterId=%s", randomId()))
+ .expectStatus().isEqualTo(422);
+ }
- var item2 = new SearchItem();
- item2.setTenantId(TENANT_ID_COLLEGE);
+ @Test
+ void titleLevelCreateWhenNoSpInDataTenants() {
+ // given
+ User requester = new User().patronGroup(PATRON_GROUP_ID);
+ wireMockServer.stubFor(get(urlMatching(USER_URL))
+ .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
+ .willReturn(jsonResponse(asJsonString(requester), SC_OK)));
+ var item1 = new SearchItem().tenantId(TENANT_ID_UNIVERSITY);
+ var item2 = new SearchItem().tenantId(TENANT_ID_COLLEGE);
var searchInstancesResponse = new SearchInstancesResponse();
searchInstancesResponse.setTotalRecords(1);
searchInstancesResponse.setInstances(List.of(new SearchInstance().items(List.of(item1, item2))));
@@ -75,330 +83,188 @@ void allowedServicePointReturnsEmptyResultWhenNoRoutingSpInResponsesFromDataTena
.withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
.willReturn(jsonResponse(asJsonString(searchInstancesResponse), SC_OK)));
- var allowedSpResponseConsortium = new AllowedServicePointsResponse();
- allowedSpResponseConsortium.setHold(Set.of(
- buildAllowedServicePoint("SP_consortium_1"),
- buildAllowedServicePoint("SP_consortium_2")));
- allowedSpResponseConsortium.setPage(null);
- allowedSpResponseConsortium.setRecall(Set.of(
- buildAllowedServicePoint("SP_consortium_3")));
-
var allowedSpResponseUniversity = new AllowedServicePointsResponse();
allowedSpResponseUniversity.setHold(null);
allowedSpResponseUniversity.setPage(null);
allowedSpResponseUniversity.setRecall(null);
+ wireMockServer.stubFor(get(urlMatching(ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
+ .withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY))
+ .willReturn(jsonResponse(asJsonString(allowedSpResponseUniversity), SC_OK)));
var allowedSpResponseCollege = new AllowedServicePointsResponse();
- allowedSpResponseCollege.setHold(null);
- allowedSpResponseCollege.setPage(null);
- allowedSpResponseCollege.setRecall(null);
+ allowedSpResponseCollege.setHold(Set.of());
+ allowedSpResponseCollege.setPage(Set.of());
+ allowedSpResponseCollege.setRecall(Set.of());
+ wireMockServer.stubFor(get(urlMatching(ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
+ .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))
+ .willReturn(jsonResponse(asJsonString(allowedSpResponseCollege), SC_OK)));
- var allowedSpResponseCollegeWithRouting = new AllowedServicePointsResponse();
- allowedSpResponseCollegeWithRouting.setHold(null);
- allowedSpResponseCollegeWithRouting.setPage(Set.of(
- buildAllowedServicePoint("SP_college_1")));
- allowedSpResponseCollegeWithRouting.setRecall(null);
+ // when - then
+ doGet(
+ ALLOWED_SERVICE_POINTS_URL + format("?operation=create&requesterId=%s&instanceId=%s",
+ REQUESTER_ID, INSTANCE_ID))
+ .expectStatus().isEqualTo(200)
+ .expectBody().json("{}");
+
+ wireMockServer.verify(getRequestedFor(urlMatching(
+ ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
+ .withQueryParam("patronGroupId", equalTo(PATRON_GROUP_ID))
+ .withQueryParam("operation", equalTo("create"))
+ .withQueryParam("instanceId", equalTo(INSTANCE_ID)));
+ }
+ @Test
+ void titleLevelCreateReturnsResponsesFromDataTenants() {
+ // given
User requester = new User().patronGroup(PATRON_GROUP_ID);
wireMockServer.stubFor(get(urlMatching(USER_URL))
.withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
.willReturn(jsonResponse(asJsonString(requester), SC_OK)));
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
+ var item1 = new SearchItem().tenantId(TENANT_ID_UNIVERSITY);
+ var item2 = new SearchItem().tenantId(TENANT_ID_COLLEGE);
+ var searchInstancesResponse = new SearchInstancesResponse();
+ searchInstancesResponse.setTotalRecords(1);
+ searchInstancesResponse.setInstances(List.of(new SearchInstance().items(List.of(item1, item2))));
+
+ wireMockServer.stubFor(get(urlMatching(SEARCH_INSTANCES_URL))
.withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
- .willReturn(jsonResponse(asJsonString(allowedSpResponseConsortium), SC_OK)));
+ .willReturn(jsonResponse(asJsonString(searchInstancesResponse), SC_OK)));
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
+ AllowedServicePointsInner sp1 = buildAllowedServicePoint("SP_college_1");
+ AllowedServicePointsInner sp2 = buildAllowedServicePoint("SP_college_2");
+ AllowedServicePointsInner sp3 = buildAllowedServicePoint("SP_college_3");
+ var allowedSpResponseUniversity = new AllowedServicePointsResponse()
+ .hold(Set.of(sp1))
+ .page(Set.of(sp1))
+ .recall(Set.of(sp2, sp3));
+ wireMockServer.stubFor(get(urlMatching(ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
.withHeader(HEADER_TENANT, equalTo(TENANT_ID_UNIVERSITY))
.willReturn(jsonResponse(asJsonString(allowedSpResponseUniversity), SC_OK)));
- var collegeStubMapping = wireMockServer.stubFor(
- get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))
- .willReturn(jsonResponse(asJsonString(allowedSpResponseCollege), SC_OK)));
-
- doGet(
- ALLOWED_SERVICE_POINTS_URL + format("?operation=create&requesterId=%s&instanceId=%s",
- REQUESTER_ID, INSTANCE_ID))
- .expectStatus().isEqualTo(200)
- .expectBody().json("{}");
-
- wireMockServer.removeStub(collegeStubMapping);
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
+ var allowedSpResponseCollege = new AllowedServicePointsResponse()
+ .hold(Set.of(sp2))
+ .page(Set.of(sp1))
+ .recall(null);
+ wireMockServer.stubFor(get(urlMatching(ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
.withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))
- .willReturn(jsonResponse(asJsonString(allowedSpResponseCollegeWithRouting),
- SC_OK)));
+ .willReturn(jsonResponse(asJsonString(allowedSpResponseCollege), SC_OK)));
+ // when - then
+ var allowedSpResponseCombined = new AllowedServicePointsResponse()
+ .hold(Set.of(sp1, sp2))
+ .page(Set.of(sp1))
+ .recall(Set.of(sp2, sp3));
doGet(
ALLOWED_SERVICE_POINTS_URL + format("?operation=create&requesterId=%s&instanceId=%s",
REQUESTER_ID, INSTANCE_ID))
.expectStatus().isEqualTo(200)
- .expectBody().json(asJsonString(allowedSpResponseConsortium));
+ .expectBody().json(asJsonString(allowedSpResponseCombined));
wireMockServer.verify(getRequestedFor(urlMatching(
- ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
+ ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
.withQueryParam("patronGroupId", equalTo(PATRON_GROUP_ID))
- .withQueryParam("instanceId", equalTo(INSTANCE_ID))
.withQueryParam("operation", equalTo("create"))
- .withQueryParam("useStubItem", equalTo("true")));
- }
-
- @Test
- void allowedServicePointsShouldReturn422WhenParametersAreInvalid() {
- doGet(ALLOWED_SERVICE_POINTS_URL + format("?operation=create&requesterId=%s", randomId()))
- .expectStatus().isEqualTo(422);
+ .withQueryParam("instanceId", equalTo(INSTANCE_ID)));
}
@Test
- void replaceForRequestLinkedToItemWhenPrimaryRequestTypeIsAllowedInBorrowingTenant() {
- createEcsTlr(true);
+ void itemLevelCreateReturnsResponsesFromDataTenants() {
+ // given
+ User requester = new User().patronGroup(PATRON_GROUP_ID);
+ wireMockServer.stubFor(get(urlMatching(USER_URL))
+ .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
+ .willReturn(jsonResponse(asJsonString(requester), SC_OK)));
- var mockAllowedSpResponseFromBorrowingTenant = new AllowedServicePointsResponse()
- .page(Set.of(buildAllowedServicePoint("borrowing-page")))
- .hold(Set.of(buildAllowedServicePoint("borrowing-hold")))
- .recall(Set.of(buildAllowedServicePoint("borrowing-recall")));
+ var searchItemResponse = new SearchItemResponse();
+ searchItemResponse.setTenantId(TENANT_ID_COLLEGE);
+ searchItemResponse.setInstanceId(INSTANCE_ID);
+ searchItemResponse.setId(ITEM_ID);
+ wireMockServer.stubFor(get(urlMatching(SEARCH_ITEM_URL))
+ .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
+ .willReturn(jsonResponse(asJsonString(searchItemResponse), SC_OK)));
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- String.format("\\?operation=replace&requestId=%s&useStubItem=true", PRIMARY_REQUEST_ID)))
- .withHeader(HEADER_TENANT, equalTo(BORROWING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromBorrowingTenant), SC_OK)));
+ AllowedServicePointsInner sp1 = buildAllowedServicePoint("SP_college_1");
+ AllowedServicePointsInner sp2 = buildAllowedServicePoint("SP_college_2");
+ var allowedSpResponseCollege = new AllowedServicePointsResponse()
+ .hold(Set.of(sp1))
+ .page(Set.of(sp1))
+ .recall(Set.of(sp2));
+ wireMockServer.stubFor(get(urlMatching(ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
+ .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))
+ .willReturn(jsonResponse(asJsonString(allowedSpResponseCollege),
+ SC_OK)));
- doGet(ALLOWED_SERVICE_POINTS_FOR_REPLACE_URL)
+ // when - then
+ doGet(
+ ALLOWED_SERVICE_POINTS_URL + format("?operation=create&requesterId=%s&itemId=%s",
+ REQUESTER_ID, ITEM_ID))
.expectStatus().isEqualTo(200)
- .expectBody()
- .jsonPath("Page").doesNotExist()
- .jsonPath("Recall").doesNotExist()
- .jsonPath("Hold").value(hasSize(1))
- .jsonPath("Hold[0].name").value(is("borrowing-hold"));
+ .expectBody().json(asJsonString(allowedSpResponseCollege));
- wireMockServer.verify(0, getRequestedFor(urlMatching(REQUEST_STORAGE_URL + ".*")));
- wireMockServer.verify(0, getRequestedFor(urlMatching(
- ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID)));
+ wireMockServer.verify(getRequestedFor(urlMatching(
+ ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
+ .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))
+ .withQueryParam("patronGroupId", equalTo(PATRON_GROUP_ID))
+ .withQueryParam("operation", equalTo("create"))
+ .withQueryParam("itemId", equalTo(ITEM_ID)));
}
@Test
- void replaceForRequestLinkedToItemWhenPrimaryRequestTypeIsNotAllowedInBorrowingTenant() {
- createEcsTlr(true);
-
+ void replaceFailsWhenEcsTlrIsNotFound() {
var mockAllowedSpResponseFromBorrowingTenant = new AllowedServicePointsResponse()
.page(Set.of(buildAllowedServicePoint("borrowing-page")))
- .hold(null)
+ .hold(Set.of(buildAllowedServicePoint("borrowing-hold")))
.recall(Set.of(buildAllowedServicePoint("borrowing-recall")));
wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- String.format("\\?operation=replace&requestId=%s&useStubItem=true", PRIMARY_REQUEST_ID)))
+ String.format("\\?operation=replace&requestId=%s", PRIMARY_REQUEST_ID)))
.withHeader(HEADER_TENANT, equalTo(BORROWING_TENANT_ID))
.willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromBorrowingTenant), SC_OK)));
doGet(ALLOWED_SERVICE_POINTS_FOR_REPLACE_URL)
- .expectStatus().isEqualTo(200)
- .expectBody()
- .jsonPath("Page").doesNotExist()
- .jsonPath("Hold").doesNotExist()
- .jsonPath("Recall").doesNotExist();
-
- wireMockServer.verify(0, getRequestedFor(urlMatching(REQUEST_STORAGE_URL + ".*")));
- wireMockServer.verify(0, getRequestedFor(urlMatching(
- ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID)));
+ .expectStatus().isEqualTo(500);
}
- @Test
- void replaceForRequestNotLinkedToItemWhenSecondaryRequestTypeIsNoLongerAllowedInLendingTenant() {
+ @ParameterizedTest
+ @EnumSource(Request.RequestTypeEnum.class)
+ void replaceForRequestNotLinkedToItem(Request.RequestTypeEnum secondaryRequestType) {
+ // given
createEcsTlr(false);
Request secondaryRequest = new Request().id(SECONDARY_REQUEST_ID)
- .requestType(Request.RequestTypeEnum.PAGE);
+ .requestType(secondaryRequestType);
wireMockServer.stubFor(get(urlMatching(REQUEST_STORAGE_URL + "/" + SECONDARY_REQUEST_ID))
.withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID))
.willReturn(jsonResponse(asJsonString(secondaryRequest), SC_OK)));
- var mockAllowedSpResponseFromLendingTenant = new AllowedServicePointsResponse()
- .page(null)
- .hold(Set.of(buildAllowedServicePoint("lending-hold")))
- .recall(Set.of(buildAllowedServicePoint("lending-recall")));
+ Set servicePoints = Set.of(
+ buildAllowedServicePoint("SP1"),
+ buildAllowedServicePoint("SP2")
+ );
+ var allowedSpResponseSecondaryRequestTenant = new AllowedServicePointsResponse();
+ switch (secondaryRequestType) {
+ case PAGE -> allowedSpResponseSecondaryRequestTenant.page(servicePoints);
+ case HOLD -> allowedSpResponseSecondaryRequestTenant.hold(servicePoints);
+ case RECALL -> allowedSpResponseSecondaryRequestTenant.recall(servicePoints);
+ }
wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- String.format("\\?operation=replace&requestId=%s&ecsRequestRouting=true", SECONDARY_REQUEST_ID)))
+ String.format("\\?operation=replace&requestId=%s", SECONDARY_REQUEST_ID)))
.withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromLendingTenant), SC_OK)));
+ .willReturn(jsonResponse(asJsonString(allowedSpResponseSecondaryRequestTenant), SC_OK)));
+ // then - then
doGet(ALLOWED_SERVICE_POINTS_FOR_REPLACE_URL)
.expectStatus().isEqualTo(200)
- .expectBody()
- .jsonPath("Page").doesNotExist()
- .jsonPath("Recall").doesNotExist()
- .jsonPath("Hold").doesNotExist();
+ .expectBody().json(asJsonString(allowedSpResponseSecondaryRequestTenant));
wireMockServer.verify(0, getRequestedFor(urlMatching(
- ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(BORROWING_TENANT_ID)));
- }
-
- @Test
- void replaceForRequestNotLinkedToItemWhenSecondaryRequestTypeIsAllowedInLendingTenant() {
- createEcsTlr(false);
-
- Request secondaryRequest = new Request().id(SECONDARY_REQUEST_ID)
- .requestType(Request.RequestTypeEnum.PAGE);
-
- wireMockServer.stubFor(get(urlMatching(REQUEST_STORAGE_URL + "/" + SECONDARY_REQUEST_ID))
- .withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(secondaryRequest), SC_OK)));
-
- var mockAllowedSpResponseFromLendingTenant = new AllowedServicePointsResponse()
- .page(Set.of(buildAllowedServicePoint("lending-page")))
- .hold(null)
- .recall(null);
-
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- String.format("\\?operation=replace&requestId=%s&ecsRequestRouting=true", SECONDARY_REQUEST_ID)))
- .withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromLendingTenant), SC_OK)));
-
- var mockAllowedSpResponseFromBorrowingTenant = new AllowedServicePointsResponse()
- .page(Set.of(buildAllowedServicePoint("borrowing-page")))
- .hold(Set.of(buildAllowedServicePoint("borrowing-hold")))
- .recall(Set.of(buildAllowedServicePoint("borrowing-recall")));
-
- wireMockServer.stubFor(
- get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- format("\\?operation=replace&requestId=%s&useStubItem=true", PRIMARY_REQUEST_ID)))
- .withHeader(HEADER_TENANT, equalTo(BORROWING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromBorrowingTenant), SC_OK)));
-
- doGet(ALLOWED_SERVICE_POINTS_FOR_REPLACE_URL)
- .expectStatus().isEqualTo(200)
- .expectBody()
- .jsonPath("Page").doesNotExist()
- .jsonPath("Recall").doesNotExist()
- .jsonPath("Hold[0].name").value(is("borrowing-hold"));
-
- wireMockServer.verify(getRequestedFor(urlMatching(
- ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
+ ALLOWED_SPS_MOD_CIRCULATION_URL_PATTERN))
.withHeader(HEADER_TENANT, equalTo(BORROWING_TENANT_ID)));
}
- @Test
- void replaceForRequestNotLinkedToItemWhenPrimaryRequestTypeIsNotAllowedInBorrowingTenant() {
- createEcsTlr(false);
-
- Request secondaryRequest = new Request().id(SECONDARY_REQUEST_ID)
- .requestType(Request.RequestTypeEnum.PAGE);
-
- wireMockServer.stubFor(get(urlMatching(REQUEST_STORAGE_URL + "/" + SECONDARY_REQUEST_ID))
- .withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(secondaryRequest), SC_OK)));
-
- var mockAllowedSpResponseFromLendingTenant = new AllowedServicePointsResponse()
- .page(Set.of(buildAllowedServicePoint("lending-page")))
- .hold(null)
- .recall(null);
-
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- String.format("\\?operation=replace&requestId=%s&ecsRequestRouting=true", SECONDARY_REQUEST_ID)))
- .withHeader(HEADER_TENANT, equalTo(LENDING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromLendingTenant), SC_OK)));
-
- var mockAllowedSpResponseFromBorrowingTenant = new AllowedServicePointsResponse()
- .page(Set.of(buildAllowedServicePoint("borrowing-page")))
- .hold(null)
- .recall(Set.of(buildAllowedServicePoint("borrowing-recall")));
-
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- String.format("\\?operation=replace&requestId=%s&useStubItem=true", PRIMARY_REQUEST_ID)))
- .withHeader(HEADER_TENANT, equalTo(BORROWING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromBorrowingTenant), SC_OK)));
-
- doGet(ALLOWED_SERVICE_POINTS_FOR_REPLACE_URL)
- .expectStatus().isEqualTo(200)
- .expectBody()
- .jsonPath("Page").doesNotExist()
- .jsonPath("Recall").doesNotExist()
- .jsonPath("Hold").doesNotExist();
- }
-
- @Test
- void replaceFailsWhenEcsTlrIsNotFound() {
- var mockAllowedSpResponseFromBorrowingTenant = new AllowedServicePointsResponse()
- .page(Set.of(buildAllowedServicePoint("borrowing-page")))
- .hold(Set.of(buildAllowedServicePoint("borrowing-hold")))
- .recall(Set.of(buildAllowedServicePoint("borrowing-recall")));
-
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL +
- String.format("\\?operation=replace&requestId=%s&useStubItem=false", PRIMARY_REQUEST_ID)))
- .withHeader(HEADER_TENANT, equalTo(BORROWING_TENANT_ID))
- .willReturn(jsonResponse(asJsonString(mockAllowedSpResponseFromBorrowingTenant), SC_OK)));
-
- doGet(ALLOWED_SERVICE_POINTS_FOR_REPLACE_URL)
- .expectStatus().isEqualTo(500);
- }
-
- @Test
- void allowedSpWithItemLevelReturnsResultSpInResponsesFromDataTenant() {
- var searchItemResponse = new SearchItemResponse();
- searchItemResponse.setTenantId(TENANT_ID_COLLEGE);
- searchItemResponse.setInstanceId(INSTANCE_ID);
- searchItemResponse.setId(ITEM_ID);
-
- wireMockServer.stubFor(get(urlMatching(SEARCH_ITEM_URL))
- .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
- .willReturn(jsonResponse(asJsonString(searchItemResponse), SC_OK)));
-
- var allowedSpResponseConsortium = new AllowedServicePointsResponse();
- allowedSpResponseConsortium.setHold(Set.of(
- buildAllowedServicePoint("SP_consortium_1"),
- buildAllowedServicePoint("SP_consortium_2")));
- allowedSpResponseConsortium.setPage(null);
- allowedSpResponseConsortium.setRecall(Set.of(
- buildAllowedServicePoint("SP_consortium_3")));
-
- var allowedSpResponseCollege = new AllowedServicePointsResponse();
- allowedSpResponseCollege.setHold(Set.of(
- buildAllowedServicePoint("SP_college_1")));
- allowedSpResponseCollege.setPage(null);
- allowedSpResponseCollege.setRecall(Set.of(
- buildAllowedServicePoint("SP_college_2")));
-
- User requester = new User().patronGroup(PATRON_GROUP_ID);
- wireMockServer.stubFor(get(urlMatching(USER_URL))
- .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
- .willReturn(jsonResponse(asJsonString(requester), SC_OK)));
-
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
- .willReturn(jsonResponse(asJsonString(allowedSpResponseConsortium), SC_OK)));
-
- wireMockServer.stubFor(get(urlMatching(ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))
- .willReturn(jsonResponse(asJsonString(allowedSpResponseCollege),
- SC_OK)));
-
- doGet(
- ALLOWED_SERVICE_POINTS_URL + format("?operation=create&requesterId=%s&itemId=%s",
- REQUESTER_ID, ITEM_ID))
- .expectStatus().isEqualTo(200)
- .expectBody().json(asJsonString(allowedSpResponseConsortium));
-
- wireMockServer.verify(getRequestedFor(urlMatching(
- ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(TENANT_ID_COLLEGE))
- .withQueryParam("patronGroupId", equalTo(PATRON_GROUP_ID))
- .withQueryParam("operation", equalTo("create"))
- .withQueryParam("ecsRequestRouting", equalTo("true"))
- .withQueryParam("itemId", equalTo(ITEM_ID)));
-
- wireMockServer.verify(getRequestedFor(urlMatching(
- ALLOWED_SERVICE_POINTS_MOD_CIRCULATION_URL_PATTERN))
- .withHeader(HEADER_TENANT, equalTo(TENANT_ID_CONSORTIUM))
- .withQueryParam("patronGroupId", equalTo(PATRON_GROUP_ID))
- .withQueryParam("instanceId", equalTo(INSTANCE_ID))
- .withQueryParam("operation", equalTo("create"))
- .withQueryParam("useStubItem", equalTo("true")));
- }
-
private AllowedServicePointsInner buildAllowedServicePoint(String name) {
return new AllowedServicePointsInner()
.id(randomId())
diff --git a/src/test/java/org/folio/controller/EcsRequestExternalControllerTest.java b/src/test/java/org/folio/controller/EcsRequestExternalControllerTest.java
new file mode 100644
index 00000000..f881d801
--- /dev/null
+++ b/src/test/java/org/folio/controller/EcsRequestExternalControllerTest.java
@@ -0,0 +1,113 @@
+package org.folio.controller;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.CREATED;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.folio.domain.dto.EcsRequestExternal;
+import org.folio.domain.dto.EcsTlr;
+import org.folio.domain.mapper.ExternalEcsRequestMapper;
+import org.folio.domain.mapper.ExternalEcsRequestMapperImpl;
+import org.folio.exception.RequestCreatingException;
+import org.folio.service.EcsTlrService;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class EcsRequestExternalControllerTest {
+ private static final String ERROR_MESSAGE = "Error message";
+ @Mock
+ private EcsTlrService ecsTlrService;
+ @Spy
+ private final ExternalEcsRequestMapper externalEcsRequestMapper =
+ new ExternalEcsRequestMapperImpl();
+ @InjectMocks
+ private EcsRequestExternalController ecsRequestExternalController;
+
+ @Test
+ void ecsRequestExternalShouldSuccessfullyBeCreatedForPageRequestType() {
+ EcsRequestExternal ecsRequestExternal = new EcsRequestExternal()
+ .instanceId(UUID.randomUUID().toString())
+ .requesterId(UUID.randomUUID().toString())
+ .requestLevel(EcsRequestExternal.RequestLevelEnum.TITLE)
+ .fulfillmentPreference(EcsRequestExternal.FulfillmentPreferenceEnum.HOLD_SHELF)
+ .requestDate(new Date());
+ EcsTlr pageEcsTlr = new EcsTlr().requestType(EcsTlr.RequestTypeEnum.PAGE);
+
+ when(ecsTlrService.create(any(EcsTlr.class)))
+ .thenReturn(pageEcsTlr);
+
+ var response = ecsRequestExternalController.postEcsRequestExternal(ecsRequestExternal);
+
+ assertEquals(CREATED, response.getStatusCode());
+ assertEquals(pageEcsTlr, response.getBody());
+ }
+
+ @Test
+ void ecsRequestExternalShouldSuccessfullyBeCreatedForRecallRequestType() {
+ EcsRequestExternal ecsRequestExternal = new EcsRequestExternal()
+ .instanceId(UUID.randomUUID().toString())
+ .requesterId(UUID.randomUUID().toString())
+ .requestLevel(EcsRequestExternal.RequestLevelEnum.TITLE)
+ .fulfillmentPreference(EcsRequestExternal.FulfillmentPreferenceEnum.HOLD_SHELF)
+ .requestDate(new Date());
+ EcsTlr recallEcsTlr = new EcsTlr().requestType(EcsTlr.RequestTypeEnum.RECALL);
+
+ when(ecsTlrService.create(any(EcsTlr.class)))
+ .thenThrow(new RequestCreatingException(ERROR_MESSAGE))
+ .thenReturn(recallEcsTlr);
+
+ var response = ecsRequestExternalController.postEcsRequestExternal(ecsRequestExternal);
+
+ assertEquals(CREATED, response.getStatusCode());
+ assertEquals(recallEcsTlr, response.getBody());
+ }
+
+ @Test
+ void ecsRequestExternalShouldSuccessfullyBeCreatedForHoldRequestType() {
+ EcsRequestExternal ecsRequestExternal = new EcsRequestExternal()
+ .instanceId(UUID.randomUUID().toString())
+ .requesterId(UUID.randomUUID().toString())
+ .requestLevel(EcsRequestExternal.RequestLevelEnum.TITLE)
+ .fulfillmentPreference(EcsRequestExternal.FulfillmentPreferenceEnum.HOLD_SHELF)
+ .requestDate(new Date());
+ EcsTlr holdEcsTlr = new EcsTlr().requestType(EcsTlr.RequestTypeEnum.HOLD);
+
+ when(ecsTlrService.create(any(EcsTlr.class)))
+ .thenThrow(new RequestCreatingException(ERROR_MESSAGE))
+ .thenThrow(new RequestCreatingException(ERROR_MESSAGE))
+ .thenReturn(holdEcsTlr);
+
+ var response = ecsRequestExternalController.postEcsRequestExternal(ecsRequestExternal);
+
+ assertEquals(CREATED, response.getStatusCode());
+ assertEquals(holdEcsTlr, response.getBody());
+ }
+
+ @Test
+ void ecsRequestExternalShouldReturnBadRequest() {
+ EcsRequestExternal ecsRequestExternal = new EcsRequestExternal()
+ .instanceId(UUID.randomUUID().toString())
+ .requesterId(UUID.randomUUID().toString())
+ .requestLevel(EcsRequestExternal.RequestLevelEnum.TITLE)
+ .fulfillmentPreference(EcsRequestExternal.FulfillmentPreferenceEnum.HOLD_SHELF)
+ .requestDate(new Date());
+
+ when(ecsTlrService.create(any(EcsTlr.class)))
+ .thenThrow(new RequestCreatingException(ERROR_MESSAGE))
+ .thenThrow(new RequestCreatingException(ERROR_MESSAGE))
+ .thenThrow(new RequestCreatingException(ERROR_MESSAGE));
+
+ assertEquals(BAD_REQUEST, ecsRequestExternalController.postEcsRequestExternal(
+ ecsRequestExternal).getStatusCode());
+ }
+}