Skip to content

Commit

Permalink
CIRC-2100 Fetch print details while fetching request details based on…
Browse files Browse the repository at this point in the history
… cql query (folio-org#1486)

* CIRC-2100 Fetching print event details for request when request is fetched by CQL query

* CIRC-2100 Fixing build issue

* CIRC-2100 Adding loggers

* CIRC-2100 Changing property name

* CIRC-2100 Code Refactoring

* CIRC-2100 Fixing NPE

* CIRC-2100 Fetching print event details only when required

* CIRC-2100 Avoiding extra user API call

* CIRC-2100 Fixing sonar issue

* CIRC-2100 code formatting

* CIRC-2100 Adding loggers

* CIRC-2100 Return 204 for post api and fixing test cases

* CIRC-2100 Changes made as per the review comments and refactoring code
  • Loading branch information
Vignesh-kalyanasundaram authored Aug 5, 2024
1 parent 4b4301b commit 5e3559d
Show file tree
Hide file tree
Showing 16 changed files with 510 additions and 24 deletions.
6 changes: 4 additions & 2 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@
},
{
"id": "circulation",
"version": "14.3",
"version": "14.4",
"handlers": [
{
"methods": [
Expand Down Expand Up @@ -2065,7 +2065,9 @@
"users.collection.get",
"addresstypes.collection.get",
"usergroups.collection.get",
"usergroups.item.get"
"usergroups.item.get",
"print-events-storage.print-events-status.item.post",
"circulation-storage.circulation-settings.collection.get"
],
"visible": false
},
Expand Down
9 changes: 9 additions & 0 deletions ramls/examples/request.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,14 @@
"callNumber": "F16.H37 A2 9001"
},
"pickupServicePointName": "Circ Desk 1"
},
"printDetails": {
"count": 4,
"lastPrintedDate": "2024-07-29T11:54:07.000Z",
"lastPrintRequester": {
"lastName": "lastName",
"firstName": "firstName",
"middleName": "middleName"
}
}
}
40 changes: 40 additions & 0 deletions ramls/request.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,46 @@
}
}
},
"printDetails": {
"description": "The print details of the request",
"type": "object",
"readonly": true,
"properties": {
"count": {
"description": "Total no of times the request is printed",
"type": "integer",
"readOnly": true
},
"lastPrintedDate": {
"description": "Recent printed time of the request",
"type": "string",
"format": "date-time",
"readOnly": true
},
"lastPrintRequester": {
"description": "Details of the User who printed the request recently",
"readonly": true,
"type": "object",
"properties": {
"firstName": {
"description": "first name of the user",
"type": "string",
"readonly": true
},
"lastName": {
"description": "last name of the user",
"type": "string",
"readonly": true
},
"middleName": {
"description": "middle name of the user",
"type": "string",
"readonly": true
}
}
}
}
},
"tags": {
"type": "object",
"description": "Tags",
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/org/folio/circulation/domain/PrintEventDetail.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.folio.circulation.domain;

import io.vertx.core.json.JsonObject;
import lombok.AllArgsConstructor;
import lombok.ToString;
import lombok.With;
import lombok.extern.log4j.Log4j2;

import java.time.ZonedDateTime;

import static org.folio.circulation.support.json.JsonPropertyFetcher.getDateTimeProperty;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getIntegerProperty;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getProperty;


@AllArgsConstructor
@Log4j2
public class PrintEventDetail {
@ToString.Include
private final JsonObject representation;
@With
private final User printeduser;

public static PrintEventDetail from(JsonObject representation) {
return new PrintEventDetail(representation, null);
}

public String getUserId() {
return getProperty(representation, "requesterId");
}

public String getRequestId() {
return getProperty(representation, "requestId");
}

public int getCount() {
return getIntegerProperty(representation, "count", 0);
}

public ZonedDateTime getPrintEventDate() {
return getDateTimeProperty(representation, "printEventDate");
}

public User getUser() {
return printeduser;
}

}
8 changes: 5 additions & 3 deletions src/main/java/org/folio/circulation/domain/Request.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,23 @@ public class Request implements ItemRelatedRecord, UserRelatedRecord {
private boolean changedPosition;
private Integer previousPosition;
private boolean changedStatus;
@With
private PrintEventDetail printEventDetail;

public static Request from(JsonObject representation) {
// TODO: make sure that operation and TLR settings don't matter for all processes calling
// this constructor
return new Request(null, null, representation, null, null, new ArrayList<>(), new HashMap<>(),
null, null, null, null, null, null, false, null,
false);
false, null);
}

public static Request from(TlrSettingsConfiguration tlrSettingsConfiguration, Operation operation,
JsonObject representation) {

return new Request(tlrSettingsConfiguration, operation, representation, null, null,
new ArrayList<>(), new HashMap<>(), null, null, null, null, null, null, false,
null, false);
null, false, null);
}

public JsonObject asJson() {
Expand Down Expand Up @@ -223,7 +225,7 @@ public Request withItem(Item newItem) {
cancellationReasonRepresentation, instance, instanceItems, instanceItemsRequestPolicies,
newItem, requester, proxy, addressType,
loan == null ? null : loan.withItem(newItem), pickupServicePoint, changedPosition,
previousPosition, changedStatus);
previousPosition, changedStatus, printEventDetail);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ public JsonObject extendedRepresentation(Request request) {
addAdditionalProxyProperties(requestRepresentation, request.getProxy());
addAdditionalServicePointProperties(requestRepresentation, request.getPickupServicePoint());
addDeliveryAddress(requestRepresentation, request, request.getRequester());
addPrintEventProperties(requestRepresentation, request.getPrintEventDetail());

removeSearchIndexFields(requestRepresentation);

return requestRepresentation;
}

Expand Down Expand Up @@ -258,5 +258,29 @@ private static JsonObject userSummary(User user) {
private static void removeSearchIndexFields(JsonObject request) {
request.remove("searchIndex");
}

private static void addPrintEventProperties(JsonObject request, PrintEventDetail printEventDetail) {
if (printEventDetail == null) {
if (log.isInfoEnabled()) {
log.info("addPrintEventProperties:: printEvent property is null for requestId {}", request.getString("id"));
}
return;
}

var printEvent = new JsonObject();
write(printEvent, "count", printEventDetail.getCount());
write(printEvent, "lastPrintedDate", printEventDetail.getPrintEventDate());

var user = printEventDetail.getUser();
if (user != null) {
var userSummary = new JsonObject();
write(userSummary, "lastName", user.getLastName());
write(userSummary, "firstName", user.getFirstName());
write(userSummary, "middleName", user.getMiddleName());
write(printEvent, "lastPrintRequester", userSummary);
}
write(request, "printDetails", printEvent);
}

}

Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
package org.folio.circulation.infrastructure.storage;

import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.circulation.domain.MultipleRecords;
import org.folio.circulation.domain.PrintEventDetail;
import org.folio.circulation.domain.PrintEventRequest;
import org.folio.circulation.domain.Request;
import org.folio.circulation.support.Clients;
import org.folio.circulation.support.CollectionResourceClient;
import org.folio.circulation.support.http.client.ResponseInterpreter;
import org.folio.circulation.support.results.Result;

import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import static java.util.concurrent.CompletableFuture.completedFuture;
import static org.folio.circulation.resources.PrintEventsResource.PRINT_EVENT_FLAG_PROPERTY_NAME;
import static org.folio.circulation.resources.PrintEventsResource.PRINT_EVENT_FLAG_QUERY;
import static org.folio.circulation.support.http.ResponseMapping.forwardOnFailure;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getProperty;
import static org.folio.circulation.support.results.Result.of;
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;

public class PrintEventsRepository {
private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());

private static final String RECORDS_PROPERTY_NAME = "printEventsStatusResponses";
private static final String REQUEST_IDS = "requestIds";
private final CollectionResourceClient printEventsStorageClient;
private final CollectionResourceClient printEventsStorageStatusClient;
private final CirculationSettingsRepository circulationSettingsRepository;

public PrintEventsRepository(Clients clients) {
printEventsStorageClient = clients.printEventsStorageClient();
this.printEventsStorageClient = clients.printEventsStorageClient();
this.printEventsStorageStatusClient = clients.printEventsStorageStatusClient();
this.circulationSettingsRepository = new CirculationSettingsRepository(clients);
}

public CompletableFuture<Result<Void>> create(PrintEventRequest printEventRequest) {
Expand All @@ -32,4 +52,54 @@ public CompletableFuture<Result<Void>> create(PrintEventRequest printEventReques
return printEventsStorageClient.post(storagePrintEventRequest).thenApply(interpreter::flatMap);
}

public CompletableFuture<Result<MultipleRecords<Request>>> findPrintEventDetails(
MultipleRecords<Request> multipleRequests) {
log.debug("findPrintEventDetails:: parameters multipleRequests: {}",
() -> multipleRecordsAsString(multipleRequests));
var requestIds = multipleRequests.toKeys(Request::getId);
if (requestIds.isEmpty()) {
log.info("fetchAndMapPrintEventDetails:: No request id found");
return completedFuture(succeeded(multipleRequests));
}
return validatePrintEventFeatureFlag()
.thenCompose(isEnabled -> Boolean.TRUE.equals(isEnabled)
? fetchAndMapPrintEventDetails(multipleRequests, requestIds)
: completedFuture(succeeded(multipleRequests)));
}

private CompletableFuture<Result<MultipleRecords<Request>>> fetchAndMapPrintEventDetails(
MultipleRecords<Request> multipleRequests, Set<String> requestIds) {
log.debug("fetchAndMapPrintEventDetails:: parameters multipleRequests: {}, requestIds {}",
() -> multipleRecordsAsString(multipleRequests), () -> requestIds);
return fetchPrintDetailsByRequestIds(requestIds)
.thenApply(printEventRecordsResult -> printEventRecordsResult
.next(printEventRecords -> mapPrintEventDetailsToRequest(printEventRecords, multipleRequests)));
}

private CompletableFuture<Boolean> validatePrintEventFeatureFlag() {
log.debug("validatePrintEventFeatureFlag:: Fetching and validating enablePrintLog flag from settings");
return circulationSettingsRepository.findBy(PRINT_EVENT_FLAG_QUERY)
.thenApply(res -> Optional.ofNullable(res.value())
.flatMap(records -> records.getRecords().stream().findFirst())
.map(setting -> Boolean.valueOf(getProperty(setting.getValue(), PRINT_EVENT_FLAG_PROPERTY_NAME)))
.orElse(false));
}

private CompletableFuture<Result<MultipleRecords<PrintEventDetail>>> fetchPrintDetailsByRequestIds
(Collection<String> requestIds) {
log.debug("fetchPrintDetailsByRequestIds:: fetching print event details for requestIds {}", requestIds);
return printEventsStorageStatusClient.post(new JsonObject().put(REQUEST_IDS, requestIds))
.thenApply(flatMapResult(response ->
MultipleRecords.from(response, PrintEventDetail::from, RECORDS_PROPERTY_NAME)));
}

private Result<MultipleRecords<Request>> mapPrintEventDetailsToRequest(
MultipleRecords<PrintEventDetail> printEventDetails, MultipleRecords<Request> requests) {
log.debug("mapPrintEventDetailsToRequest:: Mapping print event details {} with requests {}",
() -> multipleRecordsAsString(printEventDetails), () -> multipleRecordsAsString(requests));
Map<String, PrintEventDetail> printEventDetailMap = printEventDetails.toMap(PrintEventDetail::getRequestId);
return of(() ->
requests.mapRecords(request -> request
.withPrintEventDetail(printEventDetailMap.getOrDefault(request.getId(), null))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.folio.circulation.domain.ServicePoint;
import org.folio.circulation.domain.StoredRequestRepresentation;
import org.folio.circulation.domain.User;
import org.folio.circulation.infrastructure.storage.PrintEventsRepository;
import org.folio.circulation.infrastructure.storage.ServicePointRepository;
import org.folio.circulation.infrastructure.storage.inventory.InstanceRepository;
import org.folio.circulation.infrastructure.storage.inventory.ItemRepository;
Expand Down Expand Up @@ -66,6 +67,7 @@ public class RequestRepository {
private final ServicePointRepository servicePointRepository;
private final PatronGroupRepository patronGroupRepository;
private final InstanceRepository instanceRepository;
private final PrintEventsRepository printEventsRepository;

/**
* Public constructor to avoid creating repositories twice
Expand All @@ -76,7 +78,8 @@ public RequestRepository(org.folio.circulation.support.Clients clients,

this(new Clients(clients.requestsStorage(), clients.requestsBatchStorage(),
clients.cancellationReasonStorage()), itemRepository, userRepository,
loanRepository, servicePointRepository, patronGroupRepository, new InstanceRepository(clients));
loanRepository, servicePointRepository, patronGroupRepository, new InstanceRepository(clients),
new PrintEventsRepository(clients));
}

/**
Expand All @@ -87,9 +90,10 @@ public RequestRepository(org.folio.circulation.support.Clients clients) {
}

private RequestRepository(Clients clients, ItemRepository itemRepository,
UserRepository userRepository, LoanRepository loanRepository,
ServicePointRepository servicePointRepository,
PatronGroupRepository patronGroupRepository, InstanceRepository instanceRepository) {
UserRepository userRepository, LoanRepository loanRepository,
ServicePointRepository servicePointRepository,
PatronGroupRepository patronGroupRepository, InstanceRepository instanceRepository,
PrintEventsRepository printEventsRepository) {

this.requestsStorageClient = clients.getRequestsStorageClient();
this.requestsBatchStorageClient = clients.getRequestsBatchStorageClient();
Expand All @@ -100,6 +104,7 @@ private RequestRepository(Clients clients, ItemRepository itemRepository,
this.servicePointRepository = servicePointRepository;
this.patronGroupRepository = patronGroupRepository;
this.instanceRepository = instanceRepository;
this.printEventsRepository = printEventsRepository;
}

public static RequestRepository using(
Expand All @@ -113,12 +118,14 @@ public static RequestRepository using(
itemRepository, userRepository, loanRepository,
new ServicePointRepository(clients),
new PatronGroupRepository(clients),
new InstanceRepository(clients));
new InstanceRepository(clients),
new PrintEventsRepository(clients));
}

public CompletableFuture<Result<MultipleRecords<Request>>> findBy(String query) {
return requestsStorageClient.getManyWithRawQueryStringParameters(query)
.thenApply(flatMapResult(this::mapResponseToRequests))
.thenCompose(r -> r.after(this::fetchPrintEventDetails))
.thenCompose(r -> r.after(this::fetchAdditionalFields));
}

Expand All @@ -142,6 +149,14 @@ private CompletableFuture<Result<MultipleRecords<Request>>> fetchAdditionalField
.thenComposeAsync(result -> result.after(instanceRepository::findInstancesForRequests));
}

private CompletableFuture<Result<MultipleRecords<Request>>> fetchPrintEventDetails(
MultipleRecords<Request> requestRecords) {
log.debug("fetchPrintEventDetails:: Fetching print event details for requestRecords: {}",
()-> multipleRecordsAsString(requestRecords));
return ofAsync(() -> requestRecords)
.thenComposeAsync(result -> result.after(printEventsRepository::findPrintEventDetails));
}

CompletableFuture<Result<MultipleRecords<Request>>> findByWithoutItems(
CqlQuery query, PageLimit pageLimit) {

Expand Down
Loading

0 comments on commit 5e3559d

Please sign in to comment.