Skip to content

Commit

Permalink
CIRC-1932 implement search-slips endpoint skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
roman-barannyk committed Oct 31, 2023
1 parent 14a61ce commit 7a72191
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 104 deletions.
17 changes: 17 additions & 0 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@
}
]
},
{
"id": "search-slips",
"version": "0.1",
"handlers": [
{
"methods": [
"GET"
],
"pathPattern": "/circulation/search-slips/{servicePointId}",
"permissionsRequired": [
"circulation.search-slips.get"
],
"modulePermissions": [
]
}
]
},
{
"id": "request-move",
"version": "0.7",
Expand Down
26 changes: 26 additions & 0 deletions ramls/search-slips.raml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#%RAML 1.0
title: Pick Slips
version: v0.3
protocols: [ HTTP, HTTPS ]
baseUri: http://localhost:9130

documentation:
- title: API for fetching current search slips
content: <b>API for search slips generation</b>

types:
search-slips: !include pick-slips-response.json

traits:
language: !include raml-util/traits/language.raml

resourceTypes:
collection-get: !include raml-util/rtypes/collection-get.raml

/circulation:
/search-slips:
/{servicePointId}:
type:
collection-get:
exampleCollection: !include examples/pick-slips-response.json
schemaCollection: search-slips
3 changes: 3 additions & 0 deletions src/main/java/org/folio/circulation/CirculationVerticle.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.folio.circulation.resources.RequestQueueResource;
import org.folio.circulation.resources.RequestScheduledNoticeProcessingResource;
import org.folio.circulation.resources.ScheduledAnonymizationProcessingResource;
import org.folio.circulation.resources.SearchSlipsResource;
import org.folio.circulation.resources.TenantActivationResource;
import org.folio.circulation.resources.agedtolost.ScheduledAgeToLostFeeChargingResource;
import org.folio.circulation.resources.agedtolost.ScheduledAgeToLostResource;
Expand Down Expand Up @@ -100,6 +101,8 @@ public void start(Promise<Void> startFuture) {
.register(router);
new PickSlipsResource("/circulation/pick-slips/:servicePointId", client)
.register(router);
new SearchSlipsResource("/circulation/search-slips/:servicePointId", client)
.register(router);

new CirculationRulesResource("/circulation/rules", client)
.register(router);
Expand Down
109 changes: 5 additions & 104 deletions src/main/java/org/folio/circulation/resources/PickSlipsResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,19 @@

import static java.util.Collections.emptyList;
import static java.util.concurrent.CompletableFuture.completedFuture;
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.results.Result.succeeded;
import static org.folio.circulation.support.results.ResultBinding.flatMapResult;
import static org.folio.circulation.support.utils.LogUtil.collectionAsString;
import static org.folio.circulation.support.utils.LogUtil.multipleRecordsAsString;

import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
Expand All @@ -41,36 +34,20 @@
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 class PickSlipsResource extends Resource {
private static final String STATUS_KEY = "status";
private static final String ITEM_ID_KEY = "itemId";
private static final String REQUESTS_KEY = "requests";
private static final String LOCATIONS_KEY = "locations";
private static final String PICK_SLIPS_KEY = "pickSlips";
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 static final PageLimit LOCATIONS_LIMIT = PageLimit.oneThousand();
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;


Expand All @@ -85,8 +62,7 @@ public void register(Router router) {
routeRegistration.getMany(this::getMany);
}


private void getMany(RoutingContext routingContext) {
protected void getMany(RoutingContext routingContext) {
final WebContext context = new WebContext(routingContext);
final Clients clients = Clients.create(context, client);

Expand All @@ -108,22 +84,13 @@ private void getMany(RoutingContext routingContext) {
.thenComposeAsync(r -> r.after(departmentRepository::findDepartmentsForRequestUsers))
.thenComposeAsync(r -> r.after(addressTypeRepository::findAddressTypesForRequests))
.thenComposeAsync(r -> r.after(servicePointRepository::findServicePointsForRequests))
.thenApply(flatMapResult(this::mapResultToJson))
.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<Result<MultipleRecords<Location>>> fetchLocationsForServicePoint(
UUID servicePointId, Clients clients) {

log.debug("fetchLocationsForServicePoint:: parameters servicePointId: {}", servicePointId);

return findWithCqlQuery(clients.locationsStorage(), LOCATIONS_KEY, new LocationMapper()::toDomain)
.findByQuery(exactMatch(PRIMARY_SERVICE_POINT_KEY, servicePointId.toString()), LOCATIONS_LIMIT);
}

private CompletableFuture<Result<Collection<Item>>> fetchPagedItemsForLocations(
MultipleRecords<Location> multipleLocations,
ItemRepository itemRepository, LocationRepository locationRepository) {
Expand All @@ -150,48 +117,6 @@ private CompletableFuture<Result<Collection<Item>>> fetchPagedItemsForLocations(
locationRepository)));
}

private CompletableFuture<Result<Collection<Item>>> fetchLocationDetailsForItems(
MultipleRecords<Item> items, Collection<Location> locationsForServicePoint,
LocationRepository locationRepository) {

log.debug("fetchLocationDetailsForItems:: parameters items: {}",
() -> multipleRecordsAsString(items));

Set<String> locationIdsFromItems = items.toKeys(Item::getEffectiveLocationId);

Set<Location> locationsForItems = locationsForServicePoint.stream()
.filter(location -> locationIdsFromItems.contains(location.getId()))
.collect(toSet());

if (locationsForItems.isEmpty()) {
log.info("fetchLocationDetailsForItems:: locationsForItems is empty");

return completedFuture(succeeded(emptyList()));
}

return completedFuture(succeeded(locationsForItems))
.thenComposeAsync(r -> r.after(locationRepository::fetchLibraries))
.thenComposeAsync(r -> r.after(locationRepository::fetchInstitutions))
.thenComposeAsync(r -> r.after(locationRepository::fetchCampuses))
.thenApply(flatMapResult(locations -> matchLocationsToItems(items, locations)));
}

private Result<Collection<Item>> matchLocationsToItems(
MultipleRecords<Item> items, Collection<Location> locations) {

log.debug("matchLocationsToItems:: parameters items: {}, locations: {}",
() -> multipleRecordsAsString(items), () -> collectionAsString(locations));

Map<String, Location> locationsMap = locations.stream()
.collect(toMap(Location::getId, identity()));

return succeeded(
items.mapRecords(item -> item.withLocation(
locationsMap.getOrDefault(item.getEffectiveLocationId(),
Location.unknown(item.getEffectiveLocationId()))))
.getRecords());
}

private CompletableFuture<Result<MultipleRecords<Request>>> fetchOpenPageRequestsForItems(
Collection<Item> items, Clients clients) {

Expand All @@ -200,7 +125,7 @@ private CompletableFuture<Result<MultipleRecords<Request>>> fetchOpenPageRequest
.filter(StringUtils::isNoneBlank)
.collect(toSet());

if(itemIds.isEmpty()) {
if (itemIds.isEmpty()) {
log.info("fetchOpenPageRequestsForItems:: itemIds is empty");

return completedFuture(succeeded(MultipleRecords.empty()));
Expand All @@ -214,28 +139,4 @@ private CompletableFuture<Result<MultipleRecords<Request>>> fetchOpenPageRequest
.find(byIndex(ITEM_ID_KEY, itemIds).withQuery(statusAndTypeQuery))
.thenApply(flatMapResult(requests -> matchItemsToRequests(requests, items)));
}

private Result<MultipleRecords<Request>> matchItemsToRequests(
MultipleRecords<Request> requests, Collection<Item> items) {

Map<String, Item> itemMap = items.stream()
.collect(toMap(Item::getItemId, identity()));

return succeeded(
requests.mapRecords(request ->
request.withItem(itemMap.getOrDefault(request.getItemId(), null))
));
}

private Result<JsonObject> mapResultToJson(MultipleRecords<Request> requests) {
log.debug("mapResultToJson:: parameters requests: {}", () -> multipleRecordsAsString(requests));
List<JsonObject> representations = requests.getRecords().stream()
.map(TemplateContextUtil::createStaffSlipContext)
.collect(Collectors.toList());
JsonObject jsonRepresentations = new JsonObject()
.put(PICK_SLIPS_KEY, representations)
.put(TOTAL_RECORDS_KEY, representations.size());

return succeeded(jsonRepresentations);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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.lang.invoke.MethodHandles;
import java.util.concurrent.CompletableFuture;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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 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 Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());
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<Result<MultipleRecords<Request>>> fetchHoldRequests() {
return ofAsync(MultipleRecords.empty());
}
}
Loading

0 comments on commit 7a72191

Please sign in to comment.