From d73104b4751b04b0c72fc500ebb90365b66a77b1 Mon Sep 17 00:00:00 2001
From: OleksandrVidinieiev
<56632770+OleksandrVidinieiev@users.noreply.github.com>
Date: Tue, 26 Dec 2023 16:19:38 +0000
Subject: [PATCH] CIRC-1933: Implementation for Search Slips API (#1391)
* CIRC-1933 Implementation of search slips API
* CIRC-1933 Tests
* CIRC-1933 Address review comments
* CIRC-1933 Fix code smells
---
descriptors/ModuleDescriptor-template.json | 19 +-
ramls/staff-slips.raml | 8 +-
.../RequestTypeItemStatusWhiteList.java | 10 +
.../domain/notice/TemplateContextUtil.java | 16 +-
.../resources/PickSlipsResource.java | 135 +-------
.../resources/SearchSlipsResource.java | 39 +--
.../circulation/resources/SlipsResource.java | 173 ++++++++--
...ckSlipsTests.java => StaffSlipsTests.java} | 295 ++++++++++++------
8 files changed, 402 insertions(+), 293 deletions(-)
rename src/test/java/api/requests/{PickSlipsTests.java => StaffSlipsTests.java} (67%)
diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json
index 8afc4ad7c6..98e4237619 100644
--- a/descriptors/ModuleDescriptor-template.json
+++ b/descriptors/ModuleDescriptor-template.json
@@ -69,6 +69,7 @@
"circulation.search-slips.get"
],
"modulePermissions": [
+ "modperms.circulation.search-slips.get"
]
}
]
@@ -1557,7 +1558,8 @@
"circulation.requests.hold-shelf-clearance-report.get",
"circulation.requests.allowed-service-points.get",
"circulation.inventory.items-in-transit-report.get",
- "circulation.pick-slips.get"
+ "circulation.pick-slips.get",
+ "circulation.search-slips.get"
]
},
{
@@ -2321,6 +2323,21 @@
],
"visible": false
},
+ {
+ "permissionName": "modperms.circulation.search-slips.get",
+ "displayName": "module permissions for one op",
+ "description": "to reduce X-Okapi-Token size",
+ "subPermissions": [
+ "circulation.internal.fetch-items",
+ "circulation-storage.requests.item.get",
+ "circulation-storage.requests.collection.get",
+ "users.item.get",
+ "users.collection.get",
+ "addresstypes.item.get",
+ "addresstypes.collection.get"
+ ],
+ "visible": false
+ },
{
"permissionName": "circulation.internal.fetch-items",
"displayName" : "Fetch item(s)",
diff --git a/ramls/staff-slips.raml b/ramls/staff-slips.raml
index 31b5c699f3..45c1a7a023 100644
--- a/ramls/staff-slips.raml
+++ b/ramls/staff-slips.raml
@@ -1,5 +1,5 @@
#%RAML 1.0
-title: Stuff Slips
+title: Staff Slips
version: v0.3
protocols: [ HTTP, HTTPS ]
baseUri: http://localhost:9130
@@ -9,7 +9,7 @@ documentation:
content: API for staff slips generation
types:
- stuff-slips: !include staff-slips-response.json
+ staff-slips: !include staff-slips-response.json
traits:
language: !include raml-util/traits/language.raml
@@ -23,10 +23,10 @@ resourceTypes:
type:
collection-get:
exampleCollection: !include examples/staff-slips-response.json
- schemaCollection: stuff-slips
+ schemaCollection: staff-slips
/search-slips:
/{servicePointId}:
type:
collection-get:
exampleCollection: !include examples/staff-slips-response.json
- schemaCollection: stuff-slips
+ schemaCollection: staff-slips
diff --git a/src/main/java/org/folio/circulation/domain/RequestTypeItemStatusWhiteList.java b/src/main/java/org/folio/circulation/domain/RequestTypeItemStatusWhiteList.java
index 50fa6ff5d5..59b30f0aa1 100644
--- a/src/main/java/org/folio/circulation/domain/RequestTypeItemStatusWhiteList.java
+++ b/src/main/java/org/folio/circulation/domain/RequestTypeItemStatusWhiteList.java
@@ -25,6 +25,7 @@
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
+import java.util.Map;
public class RequestTypeItemStatusWhiteList {
private static EnumMap recallRules;
@@ -161,4 +162,13 @@ public static List getRequestTypesAllowedForItemStatus(ItemStatus i
.filter(requestType -> requestsRulesMap.get(requestType).get(itemStatus))
.toList();
}
+
+ public static List getItemStatusesAllowedForRequestType(RequestType requestType) {
+ return requestsRulesMap.get(requestType)
+ .entrySet()
+ .stream()
+ .filter(entry -> Boolean.TRUE.equals(entry.getValue()))
+ .map(Map.Entry::getKey)
+ .toList();
+ }
}
diff --git a/src/main/java/org/folio/circulation/domain/notice/TemplateContextUtil.java b/src/main/java/org/folio/circulation/domain/notice/TemplateContextUtil.java
index 35db89db2c..92ab3145b5 100644
--- a/src/main/java/org/folio/circulation/domain/notice/TemplateContextUtil.java
+++ b/src/main/java/org/folio/circulation/domain/notice/TemplateContextUtil.java
@@ -47,7 +47,6 @@ public class TemplateContextUtil {
private static final String FEE_ACTION = "feeAction";
private static final String UNLIMITED = "unlimited";
public static final String CURRENT_DATE_TIME = "currentDateTime";
- private static final String PICK_SLIPS_KEY = "pickSlips";
private static final String ADDITIONAL_INFO_KEY = "additionalInfo";
private TemplateContextUtil() {
@@ -120,25 +119,30 @@ public static JsonObject createStaffSlipContext(Request request) {
return createStaffSlipContext(request.getItem(), request);
}
- public static JsonObject addPrimaryServicePointNameToStaffSlipContext(JsonObject entries, ServicePoint primaryServicePoint) {
- log.debug("addPrimaryServicePointNameToStaffSlipContext:: parameters entries: {} primaryServicePoint: {}", entries, primaryServicePoint);
+ public static JsonObject addPrimaryServicePointNameToStaffSlipContext(JsonObject entries,
+ ServicePoint primaryServicePoint, String slipsCollectionName) {
+
+ log.debug("addPrimaryServicePointNameToStaffSlipContext:: parameters entries: {}, " +
+ "primaryServicePoint: {}, slipsCollectionName: {}", entries, primaryServicePoint, slipsCollectionName);
if (primaryServicePoint == null) {
log.info("addPrimaryServicePointNameToStaffSlipContext:: primaryServicePoint object is null");
return entries;
}
if (entries == null) {
- log.info("addPrimaryServicePointNameToStaffSlipContext:: entries JsonObject is null, primaryServicePointName: {}", primaryServicePoint.getName());
+ log.info("addPrimaryServicePointNameToStaffSlipContext:: entries JsonObject is null, " +
+ "primaryServicePointName: {}", primaryServicePoint.getName());
return new JsonObject();
}
- entries.getJsonArray(PICK_SLIPS_KEY)
+ entries.getJsonArray(slipsCollectionName)
.stream()
.map(JsonObject.class::cast)
.map(pickSlip -> pickSlip.getJsonObject(ITEM))
.forEach(item -> item.put("effectiveLocationPrimaryServicePointName", primaryServicePoint.getName()));
- log.info("addPrimaryServicePointNameToStaffSlipContext:: Result entries: {}, primaryServicePointName: {}", entries, primaryServicePoint.getName());
+ log.debug("addPrimaryServicePointNameToStaffSlipContext:: Result entries: {}, " +
+ "primaryServicePointName: {}", () -> entries, primaryServicePoint::getName);
return entries;
}
diff --git a/src/main/java/org/folio/circulation/resources/PickSlipsResource.java b/src/main/java/org/folio/circulation/resources/PickSlipsResource.java
index 910cccd773..b3214175b1 100644
--- a/src/main/java/org/folio/circulation/resources/PickSlipsResource.java
+++ b/src/main/java/org/folio/circulation/resources/PickSlipsResource.java
@@ -1,142 +1,13 @@
package org.folio.circulation.resources;
-import static java.util.Collections.emptyList;
-import static java.util.concurrent.CompletableFuture.completedFuture;
-import static java.util.stream.Collectors.toSet;
-import static org.folio.circulation.support.fetching.MultipleCqlIndexValuesCriteria.byIndex;
-import static org.folio.circulation.support.fetching.RecordFetching.findWithMultipleCqlIndexValues;
-import static org.folio.circulation.support.http.client.CqlQuery.exactMatch;
-import static org.folio.circulation.support.results.Result.succeeded;
-import static org.folio.circulation.support.results.ResultBinding.flatMapResult;
-import static org.folio.circulation.support.utils.LogUtil.multipleRecordsAsString;
-
-import java.lang.invoke.MethodHandles;
-import java.util.Collection;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.CompletableFuture;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.folio.circulation.domain.Item;
-import org.folio.circulation.domain.ItemStatus;
-import org.folio.circulation.domain.Location;
-import org.folio.circulation.domain.MultipleRecords;
-import org.folio.circulation.domain.Request;
-import org.folio.circulation.domain.RequestStatus;
-import org.folio.circulation.domain.RequestType;
-import org.folio.circulation.domain.notice.TemplateContextUtil;
-import org.folio.circulation.infrastructure.storage.ServicePointRepository;
-import org.folio.circulation.infrastructure.storage.inventory.ItemRepository;
-import org.folio.circulation.infrastructure.storage.inventory.LocationRepository;
-import org.folio.circulation.infrastructure.storage.users.AddressTypeRepository;
-import org.folio.circulation.infrastructure.storage.users.DepartmentRepository;
-import org.folio.circulation.infrastructure.storage.users.PatronGroupRepository;
-import org.folio.circulation.infrastructure.storage.users.UserRepository;
-import org.folio.circulation.support.Clients;
-import org.folio.circulation.support.RouteRegistration;
-import org.folio.circulation.support.http.client.CqlQuery;
-import org.folio.circulation.support.http.server.JsonHttpResponse;
-import org.folio.circulation.support.http.server.WebContext;
-import org.folio.circulation.support.results.Result;
+import static org.folio.circulation.domain.ItemStatus.PAGED;
+import static org.folio.circulation.domain.RequestType.PAGE;
import io.vertx.core.http.HttpClient;
-import io.vertx.ext.web.Router;
-import io.vertx.ext.web.RoutingContext;
public class PickSlipsResource extends SlipsResource {
- private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());
- private static final String PICK_SLIPS_KEY = "pickSlips";
- private final String rootPath;
-
public PickSlipsResource(String rootPath, HttpClient client) {
- super(client);
- this.rootPath = rootPath;
- }
-
- @Override
- public void register(Router router) {
- RouteRegistration routeRegistration = new RouteRegistration(rootPath, router);
- routeRegistration.getMany(this::getMany);
- }
-
- protected void getMany(RoutingContext routingContext) {
- final WebContext context = new WebContext(routingContext);
- final Clients clients = Clients.create(context, client);
-
- final var userRepository = new UserRepository(clients);
- final var itemRepository = new ItemRepository(clients);
- final AddressTypeRepository addressTypeRepository = new AddressTypeRepository(clients);
- final ServicePointRepository servicePointRepository = new ServicePointRepository(clients);
- final PatronGroupRepository patronGroupRepository = new PatronGroupRepository(clients);
- final DepartmentRepository departmentRepository = new DepartmentRepository(clients);
- final UUID servicePointId = UUID.fromString(
- routingContext.request().getParam(SERVICE_POINT_ID_PARAM));
-
- fetchLocationsForServicePoint(servicePointId, clients)
- .thenComposeAsync(r -> r.after(locations -> fetchPagedItemsForLocations(locations,
- itemRepository, LocationRepository.using(clients, servicePointRepository))))
- .thenComposeAsync(r -> r.after(items -> fetchOpenPageRequestsForItems(items, clients)))
- .thenComposeAsync(r -> r.after(userRepository::findUsersForRequests))
- .thenComposeAsync(result -> result.after(patronGroupRepository::findPatronGroupsForRequestsUsers))
- .thenComposeAsync(r -> r.after(departmentRepository::findDepartmentsForRequestUsers))
- .thenComposeAsync(r -> r.after(addressTypeRepository::findAddressTypesForRequests))
- .thenComposeAsync(r -> r.after(servicePointRepository::findServicePointsForRequests))
- .thenApply(flatMapResult(requests -> mapResultToJson(requests, PICK_SLIPS_KEY)))
- .thenComposeAsync(r -> r.combineAfter(() -> servicePointRepository.getServicePointById(servicePointId),
- TemplateContextUtil::addPrimaryServicePointNameToStaffSlipContext))
- .thenApply(r -> r.map(JsonHttpResponse::ok))
- .thenAccept(context::writeResultToHttpResponse);
- }
-
- private CompletableFuture>> fetchPagedItemsForLocations(
- MultipleRecords multipleLocations,
- ItemRepository itemRepository, LocationRepository locationRepository) {
-
- log.debug("fetchPagedItemsForLocations:: parameters multipleLocations: {}",
- () -> multipleRecordsAsString(multipleLocations));
- Collection locations = multipleLocations.getRecords();
-
- Set locationIds = locations.stream()
- .map(Location::getId)
- .filter(StringUtils::isNoneBlank)
- .collect(toSet());
-
- if (locationIds.isEmpty()) {
- log.info("fetchPagedItemsForLocations:: locationIds is empty");
-
- return completedFuture(succeeded(emptyList()));
- }
-
- Result statusQuery = exactMatch(STATUS_NAME_KEY, ItemStatus.PAGED.getValue());
-
- return itemRepository.findByIndexNameAndQuery(locationIds, EFFECTIVE_LOCATION_ID_KEY, statusQuery)
- .thenComposeAsync(r -> r.after(items -> fetchLocationDetailsForItems(items, locations,
- locationRepository)));
- }
-
- private CompletableFuture>> fetchOpenPageRequestsForItems(
- Collection- items, Clients clients) {
-
- Set itemIds = items.stream()
- .map(Item::getItemId)
- .filter(StringUtils::isNoneBlank)
- .collect(toSet());
-
- if (itemIds.isEmpty()) {
- log.info("fetchOpenPageRequestsForItems:: itemIds is empty");
-
- return completedFuture(succeeded(MultipleRecords.empty()));
- }
-
- final Result typeQuery = exactMatch(REQUEST_TYPE_KEY, RequestType.PAGE.getValue());
- final Result statusQuery = exactMatch(STATUS_KEY, RequestStatus.OPEN_NOT_YET_FILLED.getValue());
- final Result statusAndTypeQuery = typeQuery.combine(statusQuery, CqlQuery::and);
-
- return findWithMultipleCqlIndexValues(clients.requestsStorage(), REQUESTS_KEY, Request::from)
- .find(byIndex(ITEM_ID_KEY, itemIds).withQuery(statusAndTypeQuery))
- .thenApply(flatMapResult(requests -> matchItemsToRequests(requests, items)));
+ super(rootPath, client, "pickSlips", PAGE, PAGED);
}
}
diff --git a/src/main/java/org/folio/circulation/resources/SearchSlipsResource.java b/src/main/java/org/folio/circulation/resources/SearchSlipsResource.java
index 8fe58e5512..4b33587bd0 100644
--- a/src/main/java/org/folio/circulation/resources/SearchSlipsResource.java
+++ b/src/main/java/org/folio/circulation/resources/SearchSlipsResource.java
@@ -1,46 +1,13 @@
package org.folio.circulation.resources;
-import static org.folio.circulation.support.results.Result.ofAsync;
-import static org.folio.circulation.support.results.ResultBinding.flatMapResult;
-
-import java.util.concurrent.CompletableFuture;
-
-import org.folio.circulation.domain.MultipleRecords;
-import org.folio.circulation.domain.Request;
-import org.folio.circulation.support.RouteRegistration;
-import org.folio.circulation.support.http.server.JsonHttpResponse;
-import org.folio.circulation.support.http.server.WebContext;
-import org.folio.circulation.support.results.Result;
+import static org.folio.circulation.domain.RequestType.HOLD;
+import static org.folio.circulation.domain.RequestTypeItemStatusWhiteList.getItemStatusesAllowedForRequestType;
import io.vertx.core.http.HttpClient;
-import io.vertx.ext.web.Router;
-import io.vertx.ext.web.RoutingContext;
public class SearchSlipsResource extends SlipsResource {
- private static final String SEARCH_SLIPS_KEY = "searchSlips";
- private final String rootPath;
public SearchSlipsResource(String rootPath, HttpClient client) {
- super(client);
- this.rootPath = rootPath;
- }
-
- @Override
- public void register(Router router) {
- RouteRegistration routeRegistration = new RouteRegistration(rootPath, router);
- routeRegistration.getMany(this::getMany);
- }
-
- protected void getMany(RoutingContext routingContext) {
- final WebContext context = new WebContext(routingContext);
-
- fetchHoldRequests()
- .thenApply(flatMapResult(requests -> mapResultToJson(requests, SEARCH_SLIPS_KEY)))
- .thenApply(r -> r.map(JsonHttpResponse::ok))
- .thenAccept(context::writeResultToHttpResponse);
- }
-
- private CompletableFuture>> fetchHoldRequests() {
- return ofAsync(MultipleRecords.empty());
+ super(rootPath, client, "searchSlips", HOLD, getItemStatusesAllowedForRequestType(HOLD));
}
}
diff --git a/src/main/java/org/folio/circulation/resources/SlipsResource.java b/src/main/java/org/folio/circulation/resources/SlipsResource.java
index c8d8faead2..6b6d3c926c 100644
--- a/src/main/java/org/folio/circulation/resources/SlipsResource.java
+++ b/src/main/java/org/folio/circulation/resources/SlipsResource.java
@@ -5,8 +5,11 @@
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
+import static org.folio.circulation.support.fetching.MultipleCqlIndexValuesCriteria.byIndex;
import static org.folio.circulation.support.fetching.RecordFetching.findWithCqlQuery;
+import static org.folio.circulation.support.fetching.RecordFetching.findWithMultipleCqlIndexValues;
import static org.folio.circulation.support.http.client.CqlQuery.exactMatch;
+import static org.folio.circulation.support.http.client.CqlQuery.exactMatchAny;
import static org.folio.circulation.support.results.Result.succeeded;
import static org.folio.circulation.support.results.ResultBinding.flatMapResult;
import static org.folio.circulation.support.utils.LogUtil.collectionAsString;
@@ -20,46 +23,110 @@
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
+import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.circulation.domain.Item;
+import org.folio.circulation.domain.ItemStatus;
import org.folio.circulation.domain.Location;
import org.folio.circulation.domain.MultipleRecords;
import org.folio.circulation.domain.Request;
+import org.folio.circulation.domain.RequestStatus;
+import org.folio.circulation.domain.RequestType;
+import org.folio.circulation.domain.ServicePoint;
import org.folio.circulation.domain.notice.TemplateContextUtil;
+import org.folio.circulation.infrastructure.storage.ServicePointRepository;
+import org.folio.circulation.infrastructure.storage.inventory.ItemRepository;
import org.folio.circulation.infrastructure.storage.inventory.LocationRepository;
+import org.folio.circulation.infrastructure.storage.users.AddressTypeRepository;
+import org.folio.circulation.infrastructure.storage.users.DepartmentRepository;
+import org.folio.circulation.infrastructure.storage.users.PatronGroupRepository;
+import org.folio.circulation.infrastructure.storage.users.UserRepository;
import org.folio.circulation.storage.mappers.LocationMapper;
import org.folio.circulation.support.Clients;
+import org.folio.circulation.support.RouteRegistration;
+import org.folio.circulation.support.http.client.CqlQuery;
import org.folio.circulation.support.http.client.PageLimit;
+import org.folio.circulation.support.http.server.JsonHttpResponse;
+import org.folio.circulation.support.http.server.WebContext;
import org.folio.circulation.support.results.Result;
import io.vertx.core.http.HttpClient;
import io.vertx.core.json.JsonObject;
+import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
public abstract class SlipsResource extends Resource {
- protected static final String LOCATIONS_KEY = "locations";
- protected static final String STATUS_KEY = "status";
- protected static final String REQUESTS_KEY = "requests";
- protected static final String ITEM_ID_KEY = "itemId";
- protected static final String STATUS_NAME_KEY = "status.name";
- protected static final String REQUEST_TYPE_KEY = "requestType";
- protected static final String TOTAL_RECORDS_KEY = "totalRecords";
- protected static final String SERVICE_POINT_ID_PARAM = "servicePointId";
- protected static final String EFFECTIVE_LOCATION_ID_KEY = "effectiveLocationId";
- protected static final String PRIMARY_SERVICE_POINT_KEY = "primaryServicePoint";
-
- protected static final PageLimit LOCATIONS_LIMIT = PageLimit.oneThousand();
- protected static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());
-
-
- protected SlipsResource(HttpClient client) {
+ private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());
+ private static final PageLimit LOCATIONS_LIMIT = PageLimit.oneThousand();
+ private static final String LOCATIONS_KEY = "locations";
+ private static final String STATUS_KEY = "status";
+ private static final String REQUESTS_KEY = "requests";
+ private static final String ITEM_ID_KEY = "itemId";
+ private static final String STATUS_NAME_KEY = "status.name";
+ private static final String REQUEST_TYPE_KEY = "requestType";
+ private static final String TOTAL_RECORDS_KEY = "totalRecords";
+ private static final String SERVICE_POINT_ID_PARAM = "servicePointId";
+ private static final String EFFECTIVE_LOCATION_ID_KEY = "effectiveLocationId";
+ private static final String PRIMARY_SERVICE_POINT_KEY = "primaryServicePoint";
+
+ private final String rootPath;
+ private final String collectionName;
+ private final RequestType requestType;
+ private final Collection itemStatuses;
+
+ protected SlipsResource(String rootPath, HttpClient client, String collectionName,
+ RequestType requestType, ItemStatus itemStatus) {
+
+ this(rootPath, client, collectionName, requestType, List.of(itemStatus));
+ }
+
+ protected SlipsResource(String rootPath, HttpClient client, String collectionName,
+ RequestType requestType, Collection itemStatuses) {
+
super(client);
+ this.rootPath = rootPath;
+ this.requestType = requestType;
+ this.itemStatuses = itemStatuses;
+ this.collectionName = collectionName;
+ }
+
+ @Override
+ public void register(Router router) {
+ RouteRegistration routeRegistration = new RouteRegistration(rootPath, router);
+ routeRegistration.getMany(this::getMany);
}
- protected abstract void getMany(RoutingContext routingContext);
+ private void getMany(RoutingContext routingContext) {
+ final WebContext context = new WebContext(routingContext);
+ final Clients clients = Clients.create(context, client);
+
+ final var userRepository = new UserRepository(clients);
+ final var itemRepository = new ItemRepository(clients);
+ final var addressTypeRepository = new AddressTypeRepository(clients);
+ final var servicePointRepository = new ServicePointRepository(clients);
+ final var patronGroupRepository = new PatronGroupRepository(clients);
+ final var departmentRepository = new DepartmentRepository(clients);
+ final UUID servicePointId = UUID.fromString(
+ routingContext.request().getParam(SERVICE_POINT_ID_PARAM));
- protected CompletableFuture>> fetchLocationsForServicePoint(
+ fetchLocationsForServicePoint(servicePointId, clients)
+ .thenComposeAsync(r -> r.after(locations -> fetchItemsForLocations(locations,
+ itemRepository, LocationRepository.using(clients, servicePointRepository))))
+ .thenComposeAsync(r -> r.after(items -> fetchRequests(items, clients)))
+ .thenComposeAsync(r -> r.after(userRepository::findUsersForRequests))
+ .thenComposeAsync(result -> result.after(patronGroupRepository::findPatronGroupsForRequestsUsers))
+ .thenComposeAsync(r -> r.after(departmentRepository::findDepartmentsForRequestUsers))
+ .thenComposeAsync(r -> r.after(addressTypeRepository::findAddressTypesForRequests))
+ .thenComposeAsync(r -> r.after(servicePointRepository::findServicePointsForRequests))
+ .thenApply(flatMapResult(this::mapResultToJson))
+ .thenComposeAsync(r -> r.combineAfter(() -> servicePointRepository.getServicePointById(servicePointId),
+ this::addPrimaryServicePointNameToStaffSlipContext))
+ .thenApply(r -> r.map(JsonHttpResponse::ok))
+ .thenAccept(context::writeResultToHttpResponse);
+ }
+
+ private CompletableFuture>> fetchLocationsForServicePoint(
UUID servicePointId, Clients clients) {
log.debug("fetchLocationsForServicePoint:: parameters servicePointId: {}", servicePointId);
@@ -68,7 +135,58 @@ protected CompletableFuture>> fetchLocationsFor
.findByQuery(exactMatch(PRIMARY_SERVICE_POINT_KEY, servicePointId.toString()), LOCATIONS_LIMIT);
}
- protected CompletableFuture>> fetchLocationDetailsForItems(
+ private CompletableFuture>> fetchItemsForLocations(
+ MultipleRecords multipleLocations,
+ ItemRepository itemRepository, LocationRepository locationRepository) {
+
+ log.debug("fetchPagedItemsForLocations:: parameters multipleLocations: {}",
+ () -> multipleRecordsAsString(multipleLocations));
+ Collection locations = multipleLocations.getRecords();
+ Set locationIds = locations.stream()
+ .map(Location::getId)
+ .filter(StringUtils::isNoneBlank)
+ .collect(toSet());
+
+ if (locationIds.isEmpty()) {
+ log.info("fetchPagedItemsForLocations:: locationIds is empty");
+
+ return completedFuture(succeeded(emptyList()));
+ }
+
+ List itemStatusValues = itemStatuses.stream()
+ .map(ItemStatus::getValue)
+ .toList();
+ Result statusQuery = exactMatchAny(STATUS_NAME_KEY, itemStatusValues);
+
+ return itemRepository.findByIndexNameAndQuery(locationIds, EFFECTIVE_LOCATION_ID_KEY, statusQuery)
+ .thenComposeAsync(r -> r.after(items -> fetchLocationDetailsForItems(items, locations,
+ locationRepository)));
+ }
+
+ private CompletableFuture>> fetchRequests(
+ Collection
- items, Clients clients) {
+
+ Set itemIds = items.stream()
+ .map(Item::getItemId)
+ .filter(StringUtils::isNoneBlank)
+ .collect(toSet());
+
+ if (itemIds.isEmpty()) {
+ log.info("fetchOpenPageRequestsForItems:: itemIds is empty");
+
+ return completedFuture(succeeded(MultipleRecords.empty()));
+ }
+
+ final Result typeQuery = exactMatch(REQUEST_TYPE_KEY, requestType.getValue());
+ final Result statusQuery = exactMatch(STATUS_KEY, RequestStatus.OPEN_NOT_YET_FILLED.getValue());
+ final Result statusAndTypeQuery = typeQuery.combine(statusQuery, CqlQuery::and);
+
+ return findWithMultipleCqlIndexValues(clients.requestsStorage(), REQUESTS_KEY, Request::from)
+ .find(byIndex(ITEM_ID_KEY, itemIds).withQuery(statusAndTypeQuery))
+ .thenApply(flatMapResult(requests -> matchItemsToRequests(requests, items)));
+ }
+
+ private CompletableFuture>> fetchLocationDetailsForItems(
MultipleRecords
- items, Collection locationsForServicePoint,
LocationRepository locationRepository) {
@@ -93,7 +211,7 @@ protected CompletableFuture>> fetchLocationDetailsForIte
.thenApply(flatMapResult(locations -> matchLocationsToItems(items, locations)));
}
- protected Result> matchLocationsToItems(
+ private Result> matchLocationsToItems(
MultipleRecords
- items, Collection locations) {
log.debug("matchLocationsToItems:: parameters items: {}, locations: {}",
@@ -108,7 +226,7 @@ protected Result> matchLocationsToItems(
.getRecords());
}
- protected Result> matchItemsToRequests(
+ private Result> matchItemsToRequests(
MultipleRecords requests, Collection
- items) {
Map itemMap = items.stream()
@@ -118,17 +236,22 @@ protected Result> matchItemsToRequests(
itemMap.getOrDefault(request.getItemId(), null))));
}
- protected Result mapResultToJson(MultipleRecords requests,
- String slipsKey) {
-
+ private Result mapResultToJson(MultipleRecords requests) {
log.debug("mapResultToJson:: parameters requests: {}", () -> multipleRecordsAsString(requests));
List representations = requests.getRecords().stream()
.map(TemplateContextUtil::createStaffSlipContext)
.toList();
JsonObject jsonRepresentations = new JsonObject()
- .put(slipsKey, representations)
+ .put(collectionName, representations)
.put(TOTAL_RECORDS_KEY, representations.size());
return succeeded(jsonRepresentations);
}
+
+ private JsonObject addPrimaryServicePointNameToStaffSlipContext(JsonObject context,
+ ServicePoint servicePoint) {
+
+ return TemplateContextUtil.addPrimaryServicePointNameToStaffSlipContext(
+ context, servicePoint, collectionName);
+ }
}
diff --git a/src/test/java/api/requests/PickSlipsTests.java b/src/test/java/api/requests/StaffSlipsTests.java
similarity index 67%
rename from src/test/java/api/requests/PickSlipsTests.java
rename to src/test/java/api/requests/StaffSlipsTests.java
index f8b77b7e41..22fb0cb198 100644
--- a/src/test/java/api/requests/PickSlipsTests.java
+++ b/src/test/java/api/requests/StaffSlipsTests.java
@@ -4,6 +4,8 @@
import static java.net.HttpURLConnection.HTTP_OK;
import static java.time.ZoneOffset.UTC;
import static java.util.stream.Collectors.joining;
+import static org.folio.circulation.domain.RequestType.HOLD;
+import static org.folio.circulation.domain.RequestType.PAGE;
import static org.folio.circulation.domain.notice.TemplateContextUtil.CURRENT_DATE_TIME;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getDateTimeProperty;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getNestedStringProperty;
@@ -19,6 +21,7 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -29,6 +32,8 @@
import org.folio.circulation.domain.ItemStatus;
import org.folio.circulation.domain.Location;
import org.folio.circulation.domain.RequestStatus;
+import org.folio.circulation.domain.RequestType;
+import org.folio.circulation.domain.RequestTypeItemStatusWhiteList;
import org.folio.circulation.domain.User;
import org.folio.circulation.storage.mappers.InstanceMapper;
import org.folio.circulation.storage.mappers.LocationMapper;
@@ -38,6 +43,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
import api.support.APITests;
import api.support.builders.Address;
@@ -50,17 +57,19 @@
import api.support.matchers.UUIDMatcher;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
import lombok.val;
-class PickSlipsTests extends APITests {
+class StaffSlipsTests extends APITests {
private static final String TOTAL_RECORDS = "totalRecords";
- private static final String PICK_SLIPS_KEY = "pickSlips";
private static final String ITEM_KEY = "item";
private static final String REQUEST_KEY = "request";
private static final String REQUESTER_KEY = "requester";
- @Test
- void responseContainsNoPickSlipsForNonExistentServicePointId() {
+ @ParameterizedTest
+ @EnumSource(value = SlipsType.class)
+ void responseContainsNoSlipsForNonExistentServicePointId(SlipsType slipsType) {
UUID servicePointId = servicePointsFixture.cd1().getId();
ItemResource item = itemsFixture.basedUponSmallAngryPlanet();
@@ -71,13 +80,14 @@ void responseContainsNoPickSlipsForNonExistentServicePointId() {
.forItem(item)
.by(usersFixture.james()));
- Response response = ResourceClient.forPickSlips().getById(UUID.randomUUID());
+ Response response = slipsType.get(UUID.randomUUID());
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 0);
+ assertResponseHasItems(response, 0, slipsType);
}
- @Test
- void responseContainsNoPickSlipsForWrongServicePointId() {
+ @ParameterizedTest
+ @EnumSource(value = SlipsType.class)
+ void responseContainsNoSlipsForWrongServicePointId(SlipsType slipsType) {
UUID servicePointId = servicePointsFixture.cd1().getId();
ItemResource item = itemsFixture.basedUponSmallAngryPlanet();
@@ -89,51 +99,89 @@ void responseContainsNoPickSlipsForWrongServicePointId() {
.by(usersFixture.james()));
UUID differentServicePointId = servicePointsFixture.cd2().getId();
- Response response = ResourceClient.forPickSlips()
- .getById(differentServicePointId);
+ Response response = slipsType.get(differentServicePointId);
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 0);
+ assertResponseHasItems(response, 0, slipsType);
}
- @Test
- void responseContainsNoPickSlipsWhenThereAreNoPagedItems() {
+ @ParameterizedTest
+ @EnumSource(value = SlipsType.class)
+ void responseContainsNoSlipsWhenThereAreNoItems(SlipsType slipsType) {
UUID servicePointId = servicePointsFixture.cd1().getId();
- Response response = ResourceClient.forPickSlips().getById(servicePointId);
+ Response response = slipsType.get(servicePointId);
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 0);
+ assertResponseHasItems(response, 0, slipsType);
}
- @Test
- void responseContainsNoPickSlipsWhenItemHasOpenPageRequestWithWrongStatus() {
+ @ParameterizedTest
+ @EnumSource(value = SlipsType.class)
+ void responseContainsNoPickSlipsWhenItemHasOpenRequestWithWrongStatus(SlipsType slipsType) {
UUID servicePointId = servicePointsFixture.cd1().getId();
ItemResource item = itemsFixture.basedUponSmallAngryPlanet();
+ if (slipsType == SlipsType.SEARCH_SLIPS) {
+ checkOutFixture.checkOutByBarcode(item);
+ }
+
requestsFixture.place(new RequestBuilder()
- .page()
+ .withRequestType(slipsType.getRequestType().getValue())
+ .withStatus(RequestStatus.OPEN_AWAITING_PICKUP.getValue())
+ .withPickupServicePointId(servicePointId)
+ .forItem(item)
+ .by(usersFixture.james()));
+
+ Response response = slipsType.get(servicePointId);
+
+ assertThat(response.getStatusCode(), is(HTTP_OK));
+ assertResponseHasItems(response, 0, slipsType);
+ }
+
+ @ParameterizedTest
+ @MethodSource(value = "getAllowedStatusesForHoldRequest")
+ void responseContainsSearchSlipsForItemWithAllowedStatus(ItemStatus itemStatus) {
+ UUID servicePointId = servicePointsFixture.cd1().getId();
+ ItemResource item = itemsFixture.basedUponNod(b -> b.withStatus(itemStatus.getValue()));
+
+ requestsFixture.place(new RequestBuilder()
+ .hold()
.withStatus(RequestStatus.OPEN_AWAITING_PICKUP.getValue())
.withPickupServicePointId(servicePointId)
.forItem(item)
.by(usersFixture.james()));
- Response response = ResourceClient.forPickSlips().getById(servicePointId);
+ Response response = SlipsType.SEARCH_SLIPS.get(servicePointId);
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 0);
+ assertResponseHasItems(response, 0, SlipsType.SEARCH_SLIPS);
}
+ private static Collection getAllowedStatusesForHoldRequest() {
+ return RequestTypeItemStatusWhiteList.getItemStatusesAllowedForRequestType(HOLD)
+ .stream()
+ .filter(status -> status != ItemStatus.NONE)
+ .toList();
+ }
@ParameterizedTest
@CsvSource({
- "US, false",
- ", false",
- "XX, false",
- "US, true",
- ", true",
- "XX, true"
+ "US, false, PICK_SLIPS",
+ "US, false, SEARCH_SLIPS",
+ ", false, PICK_SLIPS",
+ ", false, SEARCH_SLIPS",
+ "XX, false, PICK_SLIPS",
+ "XX, false, SEARCH_SLIPS",
+ "US, true, PICK_SLIPS",
+ "US, true, SEARCH_SLIPS",
+ ", true, PICK_SLIPS",
+ ", true, SEARCH_SLIPS",
+ "XX, true, PICK_SLIPS",
+ "XX, true, SEARCH_SLIPS"
})
- void responseContainsPickSlipWithAllAvailableTokens(String countryCode, String primaryAddress) {
+ void responseContainsSlipWithAllAvailableTokens(String countryCode, String primaryAddress,
+ String slipsTypeName) {
+ SlipsType slipsType = SlipsType.valueOf(slipsTypeName);
IndividualResource servicePoint = servicePointsFixture.cd1();
UUID servicePointId = servicePoint.getId();
IndividualResource locationResource = locationsFixture.thirdFloor();
@@ -170,10 +218,17 @@ void responseContainsPickSlipWithAllAvailableTokens(String countryCode, String p
JsonObject lastCheckIn = itemsClient.get(itemResource.getId())
.getJson().getJsonObject("lastCheckIn");
ZonedDateTime actualCheckinDateTime = getDateTimeProperty(lastCheckIn, "dateTime");
+
+ ItemStatus expectedItemStatus = ItemStatus.PAGED;
+ if (slipsType == SlipsType.SEARCH_SLIPS) {
+ checkOutFixture.checkOutByBarcode(itemResource);
+ expectedItemStatus = ItemStatus.CHECKED_OUT;
+ }
+
IndividualResource requestResource = requestsFixture.place(new RequestBuilder()
.withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
.open()
- .page()
+ .withRequestType(slipsType.getRequestType().getValue())
.withRequestDate(requestDate)
.withRequestExpiration(requestExpiration)
.withHoldShelfExpiration(holdShelfExpiration)
@@ -183,14 +238,14 @@ void responseContainsPickSlipWithAllAvailableTokens(String countryCode, String p
.withPatronComments("I need the book")
.by(requesterResource));
- Response response = ResourceClient.forPickSlips().getById(servicePointId);
+ Response response = slipsType.get(servicePointId);
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 1);
+ assertResponseHasItems(response, 1, slipsType);
- JsonObject pickSlip = getPickSlipsList(response).get(0);
- JsonObject itemContext = pickSlip.getJsonObject(ITEM_KEY);
- assertNotNull(pickSlip.getString(CURRENT_DATE_TIME));
+ JsonObject slip = getPickSlipsList(response, slipsType).get(0);
+ JsonObject itemContext = slip.getJsonObject(ITEM_KEY);
+ assertNotNull(slip.getString(CURRENT_DATE_TIME));
ZonedDateTime requestCheckinDateTime = getDateTimeProperty(itemContext, "lastCheckedInDateTime");
@@ -207,7 +262,7 @@ void responseContainsPickSlipWithAllAvailableTokens(String countryCode, String p
assertEquals(item.getTitle(), itemContext.getString("title"));
assertEquals(item.getBarcode(), itemContext.getString("barcode"));
- assertEquals(ItemStatus.PAGED.getValue(), itemContext.getString("status"));
+ assertEquals(expectedItemStatus.getValue(), itemContext.getString("status"));
assertEquals(item.getPrimaryContributorName(), itemContext.getString("primaryContributor"));
assertEquals(contributorNames, itemContext.getString("allContributors"));
assertEquals(item.getEnumeration(), itemContext.getString("enumeration"));
@@ -228,7 +283,7 @@ void responseContainsPickSlipWithAllAvailableTokens(String countryCode, String p
assertEquals(callNumberComponents.getSuffix(), itemContext.getString("callNumberSuffix"));
User requester = new User(requesterResource.getJson());
- JsonObject requesterContext = pickSlip.getJsonObject("requester");
+ JsonObject requesterContext = slip.getJsonObject("requester");
assertThat(requesterContext.getString("firstName"), is(requester.getFirstName()));
assertThat(requesterContext.getString("lastName"), is(requester.getLastName()));
@@ -248,7 +303,7 @@ void responseContainsPickSlipWithAllAvailableTokens(String countryCode, String p
assertThat(requesterContext.getString("departments").split("; "),
arrayContainingInAnyOrder(equalTo("test department1"),equalTo("test department2")));
- JsonObject requestContext = pickSlip.getJsonObject("request");
+ JsonObject requestContext = slip.getJsonObject("request");
assertThat(requestContext.getString("deliveryAddressType"),
is(addressTypeResource.getJson().getString("addressType")));
@@ -288,15 +343,46 @@ void responseContainsPickSlipsForRequestsOfTypePageOnly() {
IndividualResource firstRequest = requestsClient.create(firstRequestBuilder);
requestsClient.create(secondRequestBuilder);
- Response response = ResourceClient.forPickSlips().getById(servicePointId);
+ Response response = SlipsType.PICK_SLIPS.get(servicePointId);
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 1);
- assertResponseContains(response, item, firstRequest, james);
+ assertResponseHasItems(response, 1, SlipsType.PICK_SLIPS);
+ assertResponseContains(response, SlipsType.PICK_SLIPS, item, firstRequest, james);
}
@Test
- void responseIncludesItemsFromDifferentLocationsForSameServicePoint() {
+ void responseContainsSearchSlipsForRequestsOfTypeHoldOnly() {
+ UUID servicePointId = servicePointsFixture.cd1().getId();
+ val item = itemsFixture.basedUponSmallAngryPlanet();
+ UserResource steve = usersFixture.steve();
+
+ RequestBuilder pageRequestBuilder = new RequestBuilder()
+ .withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
+ .page()
+ .withPickupServicePointId(servicePointId)
+ .forItem(item)
+ .by(usersFixture.james());
+
+ RequestBuilder holdRequestBuilder = new RequestBuilder()
+ .withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
+ .hold()
+ .withPickupServicePointId(servicePointId)
+ .forItem(item)
+ .by(steve);
+
+ requestsClient.create(pageRequestBuilder);
+ IndividualResource holdRequest = requestsClient.create(holdRequestBuilder);
+
+ Response response = SlipsType.SEARCH_SLIPS.get(servicePointId);
+
+ assertThat(response.getStatusCode(), is(HTTP_OK));
+ assertResponseHasItems(response, 1, SlipsType.SEARCH_SLIPS);
+ assertResponseContains(response, SlipsType.SEARCH_SLIPS, item, holdRequest, steve);
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = SlipsType.class)
+ void responseIncludesItemsFromDifferentLocationsForSameServicePoint(SlipsType slipsType) {
UUID circDesk1 = servicePointsFixture.cd1().getId();
// Circ desk 1: Second floor
@@ -309,15 +395,6 @@ void responseIncludesItemsFromDifferentLocationsForSameServicePoint() {
.withNoPermanentLocation()
.withNoTemporaryLocation());
- val james = usersFixture.james();
-
- val temeraireRequest = requestsFixture.place(new RequestBuilder()
- .withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
- .page()
- .withPickupServicePointId(circDesk1)
- .forItem(temeraireSecondFloorCd1)
- .by(james));
-
// Circ desk 1: Third floor
val thirdFloorCd1 = locationsFixture.thirdFloor();
val planetThirdFloorCd1 = itemsFixture.basedUponSmallAngryPlanet(
@@ -328,31 +405,45 @@ void responseIncludesItemsFromDifferentLocationsForSameServicePoint() {
.withNoPermanentLocation()
.withNoTemporaryLocation());
+ val james = usersFixture.james();
val charlotte = usersFixture.charlotte();
+ if (slipsType == SlipsType.SEARCH_SLIPS) {
+ checkOutFixture.checkOutByBarcode(temeraireSecondFloorCd1);
+ checkOutFixture.checkOutByBarcode(planetThirdFloorCd1);
+ }
+
+ val temeraireRequest = requestsFixture.place(new RequestBuilder()
+ .withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
+ .withRequestType(slipsType.getRequestType().getValue())
+ .withPickupServicePointId(circDesk1)
+ .forItem(temeraireSecondFloorCd1)
+ .by(james));
+
val planetRequest = requestsFixture.place(new RequestBuilder()
.withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
- .page()
+ .withRequestType(slipsType.getRequestType().getValue())
.withPickupServicePointId(circDesk1)
.forItem(planetThirdFloorCd1)
.by(charlotte));
- val response = ResourceClient.forPickSlips().getById(circDesk1);
+ val response = slipsType.get(circDesk1);
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 2);
- assertResponseContains(response, temeraireSecondFloorCd1, temeraireRequest, james);
- assertResponseContains(response, planetThirdFloorCd1, planetRequest, charlotte);
+ assertResponseHasItems(response, 2, slipsType);
+ assertResponseContains(response, slipsType, temeraireSecondFloorCd1, temeraireRequest, james);
+ assertResponseContains(response, slipsType, planetThirdFloorCd1, planetRequest, charlotte);
}
- @Test
- void responseDoesNotIncludePickSlipsFromDifferentServicePoint() {
+ @ParameterizedTest
+ @EnumSource(value = SlipsType.class)
+ void responseDoesNotIncludeSlipsFromDifferentServicePoint(SlipsType slipsType) {
UUID circDesk1 = servicePointsFixture.cd1().getId();
UUID circDesk4 = servicePointsFixture.cd4().getId();
// Circ desk 1: Third floor
val thirdFloorCd1 = locationsFixture.thirdFloor();
- val planetThirdFloorCd1 = itemsFixture.basedUponSmallAngryPlanet(
+ val temeraireThirdFloorCd1 = itemsFixture.basedUponTemeraire(
holdingBuilder -> holdingBuilder
.withPermanentLocation(thirdFloorCd1)
.withNoTemporaryLocation(),
@@ -360,15 +451,6 @@ void responseDoesNotIncludePickSlipsFromDifferentServicePoint() {
.withNoPermanentLocation()
.withNoTemporaryLocation());
- val charlotte = usersFixture.charlotte();
-
- val requestForThirdFloorCd1 = requestsFixture.place(new RequestBuilder()
- .withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
- .page()
- .withPickupServicePointId(circDesk1)
- .forItem(planetThirdFloorCd1)
- .by(charlotte));
-
// Circ desk 4: Second floor
val secondFloorCd4 = locationsFixture.fourthServicePoint();
val planetSecondFloorCd4 = itemsFixture.basedUponSmallAngryPlanet(
@@ -379,32 +461,46 @@ void responseDoesNotIncludePickSlipsFromDifferentServicePoint() {
.withNoPermanentLocation()
.withNoTemporaryLocation());
- val jessica = usersFixture.jessica();
+ if (slipsType == SlipsType.SEARCH_SLIPS) {
+ checkOutFixture.checkOutByBarcode(temeraireThirdFloorCd1);
+ checkOutFixture.checkOutByBarcode(planetSecondFloorCd4);
+ }
+
+ val charlotte = usersFixture.charlotte();
+ val steve = usersFixture.steve();
+
+ val requestForThirdFloorCd1 = requestsFixture.place(new RequestBuilder()
+ .withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
+ .withRequestType(slipsType.getRequestType().getValue())
+ .withPickupServicePointId(circDesk1)
+ .forItem(temeraireThirdFloorCd1)
+ .by(charlotte));
val requestForSecondFloorCd4 = requestsFixture.place(new RequestBuilder()
.withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
- .page()
+ .withRequestType(slipsType.getRequestType().getValue())
.withPickupServicePointId(circDesk1)
.forItem(planetSecondFloorCd4)
- .by(jessica));
+ .by(steve));
// response for Circ Desk 1
- val responseForCd1 = ResourceClient.forPickSlips().getById(circDesk1);
+ val responseForCd1 = slipsType.get(circDesk1);
assertThat(responseForCd1.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(responseForCd1, 1);
- assertResponseContains(responseForCd1, planetThirdFloorCd1, requestForThirdFloorCd1, charlotte);
+ assertResponseHasItems(responseForCd1, 1, slipsType);
+ assertResponseContains(responseForCd1, slipsType, temeraireThirdFloorCd1, requestForThirdFloorCd1, charlotte);
// response for Circ Desk 4
- val responseForCd4 = ResourceClient.forPickSlips().getById(circDesk4);
+ val responseForCd4 = slipsType.get(circDesk4);
assertThat(responseForCd4.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(responseForCd4, 1);
- assertResponseContains(responseForCd4, planetSecondFloorCd4, requestForSecondFloorCd4, jessica);
+ assertResponseHasItems(responseForCd4, 1, slipsType);
+ assertResponseContains(responseForCd4, slipsType, planetSecondFloorCd4, requestForSecondFloorCd4, steve);
}
- @Test
- void responseContainsPickSlipsWhenServicePointHasManyLocations() {
+ @ParameterizedTest
+ @EnumSource(value = SlipsType.class)
+ void responseContainsSlipsWhenServicePointHasManyLocations(SlipsType slipsType) {
final UUID servicePointId = servicePointsFixture.cd1().getId();
final int numberOfLocations = 100;
@@ -428,34 +524,38 @@ void responseContainsPickSlipsWhenServicePointHasManyLocations() {
RequestBuilder pageRequestBuilder = new RequestBuilder()
.withStatus(RequestStatus.OPEN_NOT_YET_FILLED.getValue())
- .page()
+ .withRequestType(slipsType.getRequestType().getValue())
.withPickupServicePointId(servicePointId)
.forItem(item)
.by(james);
+ if (slipsType == SlipsType.SEARCH_SLIPS) {
+ checkOutFixture.checkOutByBarcode(item);
+ }
+
val pageRequest = requestsClient.create(pageRequestBuilder);
- val response = ResourceClient.forPickSlips().getById(servicePointId);
+ val response = slipsType.get(servicePointId);
assertThat(response.getStatusCode(), is(HTTP_OK));
- assertResponseHasItems(response, 1);
- assertResponseContains(response, item, pageRequest, james);
+ assertResponseHasItems(response, 1, slipsType);
+ assertResponseContains(response, slipsType, item, pageRequest, james);
}
private void assertDatetimeEquivalent(ZonedDateTime firstDateTime, ZonedDateTime secondDateTime) {
assertThat(firstDateTime.compareTo(secondDateTime), is(0));
}
- private void assertResponseHasItems(Response response, int itemsCount) {
+ private void assertResponseHasItems(Response response, int itemsCount, SlipsType slipsType) {
JsonObject responseJson = response.getJson();
- assertThat(responseJson.getJsonArray(PICK_SLIPS_KEY).size(), is(itemsCount));
+ assertThat(responseJson.getJsonArray(slipsType.getCollectionName()).size(), is(itemsCount));
assertThat(responseJson.getInteger(TOTAL_RECORDS), is(itemsCount));
}
- private void assertResponseContains(Response response, ItemResource item,
+ private void assertResponseContains(Response response, SlipsType slipsType, ItemResource item,
IndividualResource request, UserResource requester) {
- long count = getPickSlipsStream(response)
+ long count = getSlipsStream(response, slipsType)
.filter(ps ->
item.getBarcode().equals(
getNestedStringProperty(ps, ITEM_KEY, "barcode"))
@@ -476,16 +576,33 @@ private void assertResponseContains(Response response, ItemResource item,
}
}
- private Stream getPickSlipsStream(Response response) {
- return JsonObjectArrayPropertyFetcher.toStream(response.getJson(), PICK_SLIPS_KEY);
+ private Stream getSlipsStream(Response response, SlipsType slipsType) {
+ return JsonObjectArrayPropertyFetcher.toStream(response.getJson(), slipsType.getCollectionName());
}
- private List getPickSlipsList(Response response) {
- return getPickSlipsStream(response)
+ private List getPickSlipsList(Response response, SlipsType slipsType) {
+ return getSlipsStream(response, slipsType)
.collect(Collectors.toList());
}
private String getName(JsonObject jsonObject) {
return jsonObject.getString("name");
}
+
+ @AllArgsConstructor
+ private enum SlipsType {
+ PICK_SLIPS(ResourceClient.forPickSlips(), "pickSlips", PAGE),
+ SEARCH_SLIPS(ResourceClient.forSearchSlips(), "searchSlips", HOLD);
+
+ private final ResourceClient client;
+ @Getter
+ private final String collectionName;
+ @Getter
+ private final RequestType requestType;
+
+ private Response get(UUID servicePointId) {
+ return client.getById(servicePointId);
+ }
+
+ }
}