diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index f2e3bb42e7..95fccc6e00 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -1222,7 +1222,7 @@ }, { "id": "request-storage", - "version": "6.0" + "version": "6.1" }, { "id": "request-storage-batch", @@ -2065,9 +2065,7 @@ "users.collection.get", "addresstypes.collection.get", "usergroups.collection.get", - "usergroups.item.get", - "print-events-storage.print-events-status.item.post", - "circulation-storage.circulation-settings.collection.get" + "usergroups.item.get" ], "visible": false }, diff --git a/ramls/examples/request.json b/ramls/examples/request.json index 228c97f1b7..2072c6b617 100644 --- a/ramls/examples/request.json +++ b/ramls/examples/request.json @@ -47,11 +47,13 @@ "pickupServicePointName": "Circ Desk 1" }, "printDetails": { - "count": 4, - "lastPrintedDate": "2024-07-29T11:54:07.000Z", + "printCount": 32, + "requesterId": "21457ab5-4635-4e56-906a-908f05e9233b", + "isPrinted": true, + "printEventDate": "2024-09-13T06:34:16.035+00:00", "lastPrintRequester": { - "lastName": "lastName", "firstName": "firstName", + "lastName": "lastName", "middleName": "middleName" } } diff --git a/ramls/request.json b/ramls/request.json index 1b80913dbb..fb0d7b7a08 100644 --- a/ramls/request.json +++ b/ramls/request.json @@ -363,12 +363,22 @@ "type": "object", "readonly": true, "properties": { - "count": { + "printCount": { "description": "Total no of times the request is printed", "type": "integer", "readOnly": true }, - "lastPrintedDate": { + "requesterId": { + "description": "User uuid of last print requester", + "type": "string", + "readOnly": true + }, + "isPrinted": { + "description": "Whether the request is ever printed", + "type": "boolean", + "readOnly": true + }, + "printEventDate": { "description": "Recent printed time of the request", "type": "string", "format": "date-time", diff --git a/src/main/java/org/folio/circulation/domain/PrintEventDetail.java b/src/main/java/org/folio/circulation/domain/PrintEventDetail.java deleted file mode 100644 index b52a440c30..0000000000 --- a/src/main/java/org/folio/circulation/domain/PrintEventDetail.java +++ /dev/null @@ -1,48 +0,0 @@ -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; - } - -} diff --git a/src/main/java/org/folio/circulation/domain/Request.java b/src/main/java/org/folio/circulation/domain/Request.java index d1cecb8085..b604a37548 100644 --- a/src/main/java/org/folio/circulation/domain/Request.java +++ b/src/main/java/org/folio/circulation/domain/Request.java @@ -102,8 +102,9 @@ public class Request implements ItemRelatedRecord, UserRelatedRecord { private boolean changedPosition; private Integer previousPosition; private boolean changedStatus; + @With - private PrintEventDetail printEventDetail; + private final User printDetailsRequester; public static Request from(JsonObject representation) { // TODO: make sure that operation and TLR settings don't matter for all processes calling @@ -225,7 +226,7 @@ public Request withItem(Item newItem) { cancellationReasonRepresentation, instance, instanceItems, instanceItemsRequestPolicies, newItem, requester, proxy, addressType, loan == null ? null : loan.withItem(newItem), pickupServicePoint, changedPosition, - previousPosition, changedStatus, printEventDetail); + previousPosition, changedStatus, null); } @Override @@ -243,6 +244,10 @@ public User getUser() { return getRequester(); } + public User getPrintDetailsRequester() { + return printDetailsRequester; + } + public String getfulfillmentPreferenceName() { return requestRepresentation.getString("fulfillmentPreference"); } @@ -291,6 +296,10 @@ public JsonObject getRequesterFromRepresentation() { return requestRepresentation.getJsonObject("requester"); } + public JsonObject getPrintDetails() { + return requestRepresentation.getJsonObject("printDetails"); + } + public String getRequesterBarcode() { return getRequesterFromRepresentation().getString("barcode", EMPTY); } diff --git a/src/main/java/org/folio/circulation/domain/RequestRepresentation.java b/src/main/java/org/folio/circulation/domain/RequestRepresentation.java index 6a51004c10..2f03abc5c6 100644 --- a/src/main/java/org/folio/circulation/domain/RequestRepresentation.java +++ b/src/main/java/org/folio/circulation/domain/RequestRepresentation.java @@ -33,12 +33,33 @@ public JsonObject extendedRepresentation(Request request) { addAdditionalProxyProperties(requestRepresentation, request.getProxy()); addAdditionalServicePointProperties(requestRepresentation, request.getPickupServicePoint()); addDeliveryAddress(requestRepresentation, request, request.getRequester()); - addPrintEventProperties(requestRepresentation, request.getPrintEventDetail()); + addPrintDetailsProperties(request, requestRepresentation); removeSearchIndexFields(requestRepresentation); + return requestRepresentation; } + private void addPrintDetailsProperties(Request request, JsonObject requestRepresentation) { + JsonObject printDetails = requestRepresentation.getJsonObject("printDetails"); + if (printDetails == null) { + if (log.isInfoEnabled()) { + log.info("addPrintEventProperties:: printDetails property is null for" + + " requestId {}", requestRepresentation.getString("id")); + } + return; + } + + User printDetailsUser = request.getPrintDetailsRequester(); + if (printDetailsUser != null) { + JsonObject lastPrintRequester = new JsonObject(); + lastPrintRequester.put("firstName", printDetailsUser.getFirstName()); + lastPrintRequester.put("lastName", printDetailsUser.getLastName()); + lastPrintRequester.put("middleName", printDetailsUser.getMiddleName()); + printDetails.put("lastPrintRequester", lastPrintRequester); + } + } + private static void addAdditionalRequesterProperties(JsonObject request, User requester) { if (requester == null) { String msg = "Unable to add requester properties to the request: {}, requester is null."; @@ -258,29 +279,5 @@ 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); - } - } diff --git a/src/main/java/org/folio/circulation/infrastructure/storage/PrintEventsRepository.java b/src/main/java/org/folio/circulation/infrastructure/storage/PrintEventsRepository.java index 8622357131..1a179857ff 100644 --- a/src/main/java/org/folio/circulation/infrastructure/storage/PrintEventsRepository.java +++ b/src/main/java/org/folio/circulation/infrastructure/storage/PrintEventsRepository.java @@ -1,46 +1,26 @@ 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) { - this.printEventsStorageClient = clients.printEventsStorageClient(); - this.printEventsStorageStatusClient = clients.printEventsStorageStatusClient(); - this.circulationSettingsRepository = new CirculationSettingsRepository(clients); + printEventsStorageClient = clients.printEventsStorageClient(); } public CompletableFuture> create(PrintEventRequest printEventRequest) { @@ -52,54 +32,4 @@ public CompletableFuture> create(PrintEventRequest printEventReques return printEventsStorageClient.post(storagePrintEventRequest).thenApply(interpreter::flatMap); } - public CompletableFuture>> findPrintEventDetails( - MultipleRecords 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>> fetchAndMapPrintEventDetails( - MultipleRecords multipleRequests, Set requestIds) { - log.debug("fetchAndMapPrintEventDetails:: parameters multipleRequests: {}, requestIds {}", - () -> multipleRecordsAsString(multipleRequests), () -> requestIds); - return fetchPrintDetailsByRequestIds(requestIds) - .thenApply(printEventRecordsResult -> printEventRecordsResult - .next(printEventRecords -> mapPrintEventDetailsToRequest(printEventRecords, multipleRequests))); - } - - private CompletableFuture 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>> fetchPrintDetailsByRequestIds - (Collection 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> mapPrintEventDetailsToRequest( - MultipleRecords printEventDetails, MultipleRecords requests) { - log.debug("mapPrintEventDetailsToRequest:: Mapping print event details {} with requests {}", - () -> multipleRecordsAsString(printEventDetails), () -> multipleRecordsAsString(requests)); - Map printEventDetailMap = printEventDetails.toMap(PrintEventDetail::getRequestId); - return of(() -> - requests.mapRecords(request -> request - .withPrintEventDetail(printEventDetailMap.getOrDefault(request.getId(), null)))); - } } diff --git a/src/main/java/org/folio/circulation/infrastructure/storage/requests/RequestRepository.java b/src/main/java/org/folio/circulation/infrastructure/storage/requests/RequestRepository.java index c17aa06dc5..208c2bf0da 100644 --- a/src/main/java/org/folio/circulation/infrastructure/storage/requests/RequestRepository.java +++ b/src/main/java/org/folio/circulation/infrastructure/storage/requests/RequestRepository.java @@ -30,7 +30,6 @@ 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; @@ -67,7 +66,6 @@ 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 @@ -78,8 +76,7 @@ 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), - new PrintEventsRepository(clients)); + loanRepository, servicePointRepository, patronGroupRepository, new InstanceRepository(clients)); } /** @@ -90,10 +87,9 @@ public RequestRepository(org.folio.circulation.support.Clients clients) { } private RequestRepository(Clients clients, ItemRepository itemRepository, - UserRepository userRepository, LoanRepository loanRepository, - ServicePointRepository servicePointRepository, - PatronGroupRepository patronGroupRepository, InstanceRepository instanceRepository, - PrintEventsRepository printEventsRepository) { + UserRepository userRepository, LoanRepository loanRepository, + ServicePointRepository servicePointRepository, + PatronGroupRepository patronGroupRepository, InstanceRepository instanceRepository) { this.requestsStorageClient = clients.getRequestsStorageClient(); this.requestsBatchStorageClient = clients.getRequestsBatchStorageClient(); @@ -104,7 +100,6 @@ private RequestRepository(Clients clients, ItemRepository itemRepository, this.servicePointRepository = servicePointRepository; this.patronGroupRepository = patronGroupRepository; this.instanceRepository = instanceRepository; - this.printEventsRepository = printEventsRepository; } public static RequestRepository using( @@ -118,14 +113,12 @@ public static RequestRepository using( itemRepository, userRepository, loanRepository, new ServicePointRepository(clients), new PatronGroupRepository(clients), - new InstanceRepository(clients), - new PrintEventsRepository(clients)); + new InstanceRepository(clients)); } public CompletableFuture>> findBy(String query) { return requestsStorageClient.getManyWithRawQueryStringParameters(query) .thenApply(flatMapResult(this::mapResponseToRequests)) - .thenCompose(r -> r.after(this::fetchPrintEventDetails)) .thenCompose(r -> r.after(this::fetchAdditionalFields)); } @@ -149,14 +142,6 @@ private CompletableFuture>> fetchAdditionalField .thenComposeAsync(result -> result.after(instanceRepository::findInstancesForRequests)); } - private CompletableFuture>> fetchPrintEventDetails( - MultipleRecords requestRecords) { - log.debug("fetchPrintEventDetails:: Fetching print event details for requestRecords: {}", - ()-> multipleRecordsAsString(requestRecords)); - return ofAsync(() -> requestRecords) - .thenComposeAsync(result -> result.after(printEventsRepository::findPrintEventDetails)); - } - CompletableFuture>> findByWithoutItems( CqlQuery query, PageLimit pageLimit) { diff --git a/src/main/java/org/folio/circulation/infrastructure/storage/users/UserRepository.java b/src/main/java/org/folio/circulation/infrastructure/storage/users/UserRepository.java index 8e8256f990..190d39e91d 100644 --- a/src/main/java/org/folio/circulation/infrastructure/storage/users/UserRepository.java +++ b/src/main/java/org/folio/circulation/infrastructure/storage/users/UserRepository.java @@ -19,11 +19,13 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; + +import io.vertx.core.json.JsonObject; import org.folio.circulation.domain.Loan; import org.folio.circulation.domain.MultipleRecords; -import org.folio.circulation.domain.PrintEventDetail; import org.folio.circulation.domain.Request; import org.folio.circulation.domain.User; import org.folio.circulation.domain.UserRelatedRecord; @@ -42,6 +44,7 @@ public class UserRepository { private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass()); private static final String USERS_RECORD_PROPERTY = "users"; + private static final String REQUESTER_ID = "requesterId"; private final CollectionResourceClient usersStorageClient; @@ -272,8 +275,10 @@ private ArrayList getUsersFromRequest(Request request) { usersToFetch.add(request.getProxyUserId()); } - if (request.getPrintEventDetail() != null && request.getPrintEventDetail().getUserId() != null) { - usersToFetch.add(request.getPrintEventDetail().getUserId()); + JsonObject printDetails = request.getPrintDetails(); + if (printDetails != null && + StringUtils.isNotBlank(printDetails.getString(REQUESTER_ID))) { + usersToFetch.add(printDetails.getString(REQUESTER_ID)); } return usersToFetch; @@ -288,13 +293,9 @@ private Request matchUsersToRequests( return request .withRequester(userMap.getOrDefault(request.getUserId(), null)) .withProxy(userMap.getOrDefault(request.getProxyUserId(), null)) - .withPrintEventDetail(mapUserToPrintEventDetails(request, userMap)); - } - - private PrintEventDetail mapUserToPrintEventDetails(Request request, Map userMap) { - var printEventDetail = request.getPrintEventDetail(); - return printEventDetail != null ? - printEventDetail.withPrinteduser(userMap.getOrDefault(printEventDetail.getUserId(), null)) : null; + .withPrintDetailsRequester(userMap + .getOrDefault(Optional.ofNullable(request.getPrintDetails()) + .map(pd -> pd.getString(REQUESTER_ID)).orElse(null), null)); } private Result> mapResponseToUsers(Response response) { diff --git a/src/main/java/org/folio/circulation/resources/PrintEventsResource.java b/src/main/java/org/folio/circulation/resources/PrintEventsResource.java index b530e20110..605919b60b 100644 --- a/src/main/java/org/folio/circulation/resources/PrintEventsResource.java +++ b/src/main/java/org/folio/circulation/resources/PrintEventsResource.java @@ -30,11 +30,11 @@ public class PrintEventsResource extends Resource { private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass()); - public static final String PRINT_EVENT_FLAG_QUERY = "query=name=printEventLogFeature"; + private static final String PRINT_EVENT_FLAG_QUERY = "query=name=printEventLogFeature"; private static final String PRINT_EVENT_FEATURE_DISABLED_ERROR = "print event feature is disabled for this tenant"; private static final String NO_CONFIG_FOUND_ERROR = "No configuration found for print event feature"; private static final String MULTIPLE_CONFIGS_ERROR = "Multiple configurations found for print event feature"; - public static final String PRINT_EVENT_FLAG_PROPERTY_NAME = "enablePrintLog"; + private static final String PRINT_EVENT_FLAG_PROPERTY_NAME = "enablePrintLog"; public PrintEventsResource(HttpClient client) { super(client); diff --git a/src/main/java/org/folio/circulation/resources/RequestFromRepresentationService.java b/src/main/java/org/folio/circulation/resources/RequestFromRepresentationService.java index 255b015535..a11b86d231 100644 --- a/src/main/java/org/folio/circulation/resources/RequestFromRepresentationService.java +++ b/src/main/java/org/folio/circulation/resources/RequestFromRepresentationService.java @@ -578,6 +578,10 @@ private Request removeRelatedRecordInformation(Request request) { representation.remove("pickupServicePoint"); representation.remove("deliveryAddress"); + JsonObject printDetails = representation.getJsonObject("printDetails"); + if (printDetails != null && printDetails.containsKey("lastPrintRequester")) { + printDetails.remove("lastPrintRequester"); + } return request; } diff --git a/src/main/java/org/folio/circulation/support/Clients.java b/src/main/java/org/folio/circulation/support/Clients.java index 9ff7028965..99be88183c 100644 --- a/src/main/java/org/folio/circulation/support/Clients.java +++ b/src/main/java/org/folio/circulation/support/Clients.java @@ -71,7 +71,7 @@ public class Clients { private final GetManyRecordsClient settingsStorageClient; private final CollectionResourceClient circulationSettingsStorageClient; private final CollectionResourceClient printEventsStorageClient; - private final CollectionResourceClient printEventsStorageStatusClient; + public static Clients create(WebContext context, HttpClient httpClient) { return new Clients(context.createHttpClient(httpClient), context); @@ -141,7 +141,7 @@ private Clients(OkapiHttpClient client, WebContext context) { circulationItemClient = createCirculationItemClient(client, context); circulationSettingsStorageClient = createCirculationSettingsStorageClient(client, context); printEventsStorageClient = createPrintEventsStorageClient(client, context); - printEventsStorageStatusClient = createPrintEventsStorageStatusClient(client, context); + } catch(MalformedURLException e) { throw new InvalidOkapiLocationException(context.getOkapiLocation(), e); @@ -388,10 +388,6 @@ public CollectionResourceClient printEventsStorageClient() { return printEventsStorageClient; } - public CollectionResourceClient printEventsStorageStatusClient() { - return printEventsStorageStatusClient; - } - private static CollectionResourceClient getCollectionResourceClient( OkapiHttpClient client, WebContext context, String path) @@ -833,13 +829,6 @@ private CollectionResourceClient createPrintEventsStorageClient( "/print-events-storage/print-events-entry"); } - private CollectionResourceClient createPrintEventsStorageStatusClient( - OkapiHttpClient client, WebContext context) throws MalformedURLException { - - return getCollectionResourceClient(client, context, - "/print-events-storage/print-events-status"); - } - private GetManyRecordsClient createSettingsStorageClient( OkapiHttpClient client, WebContext context) throws MalformedURLException { diff --git a/src/test/java/api/requests/RequestsAPICreationTests.java b/src/test/java/api/requests/RequestsAPICreationTests.java index a7493260b7..7b08979d85 100644 --- a/src/test/java/api/requests/RequestsAPICreationTests.java +++ b/src/test/java/api/requests/RequestsAPICreationTests.java @@ -16,7 +16,6 @@ import static api.support.fixtures.TemplateContextMatchers.getUserContextMatchers; import static api.support.http.CqlQuery.exactMatch; import static api.support.http.CqlQuery.notEqual; -import static api.support.http.InterfaceUrls.printEventsUrl; import static api.support.http.Limit.limit; import static api.support.http.Offset.noOffset; import static api.support.matchers.EventMatchers.isValidLoanDueDateChangedEvent; @@ -108,7 +107,6 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -import api.support.builders.CirculationSettingBuilder; import org.apache.http.HttpStatus; import org.awaitility.Awaitility; import org.folio.circulation.domain.ItemStatus; @@ -196,7 +194,6 @@ public class RequestsAPICreationTests extends APITests { public void afterEach() { mockClockManagerToReturnDefaultDateTime(); configurationsFixture.deleteTlrFeatureConfig(); - circulationSettingsClient.deleteAll(); } @Test @@ -232,7 +229,10 @@ void canCreateARequest() { .withHoldShelfExpiration(LocalDate.of(2017, 8, 31)) .withPickupServicePointId(pickupServicePointId) .withTags(new RequestBuilder.Tags(asList("new", "important"))) - .withPatronComments("I need this book")); + .withPatronComments("I need this book") + .withPrintDetails(new RequestBuilder.PrintDetails(49, + requester.getId().toString(), true, "2024-09-16T11:58:22" + + ".295+00:00"))); JsonObject representation = request.getJson(); @@ -4862,124 +4862,6 @@ void createHoldRequestForDcbItemAndResponseContainsDcbTitle() { } - @Test - void fetchRequestWithOutPrintEventFeature() { - assertThat("Circulation settings enabled", circulationSettingsClient.getAll().isEmpty()); - var barcode1 = "barcode1"; - var barcode2 = "barcode2"; - // creating 2 different requests and assert request details without enabling printEvent feature - var userResource = usersFixture.charlotte(); - var servicePointId = servicePointsFixture.cd1().getId(); - var requestId1 = createRequest(userResource, barcode1, servicePointId).getId(); - var requestId2 = createRequest(userResource, barcode2, servicePointId).getId(); - - JsonObject requestRepresentation1 = requestsClient.getMany(exactMatch("id", requestId1.toString())).getFirst(); - JsonObject requestRepresentation2 = requestsClient.getMany(exactMatch("id", requestId2.toString())).getFirst(); - assertRequestDetails(requestRepresentation1, requestId1, barcode1, servicePointId); - assertRequestDetails(requestRepresentation2, requestId2, barcode2, servicePointId); - assertThat("printDetails should be null for request1 because the print event feature is not enabled", - requestRepresentation1.getJsonObject("printDetails"), Matchers.nullValue()); - assertThat("printDetails should be null for request2 because the print event feature is not enabled", - requestRepresentation2.getJsonObject("printDetails"), Matchers.nullValue()); - } - - @Test - void printAndFetchDetailWithPrintEventFeatureEnabled() { - assertThat("Circulation settings enabled", circulationSettingsClient.getAll().isEmpty()); - var barcode1 = "barcode1"; - var barcode2 = "barcode2"; - // creating 2 different requests and print those 2 requests - // assert request details with enabling printEvent feature - circulationSettingsClient.create(new CirculationSettingBuilder() - .withName("printEventLogFeature") - .withValue(new JsonObject().put("enablePrintLog", true))); - var userResource1 = usersFixture.charlotte(); - var userResource2 = usersFixture.jessica(); - var servicePointId = servicePointsFixture.cd1().getId(); - var requestId1 = createRequest(userResource1, barcode1, servicePointId).getId(); - var requestId2 = createRequest(userResource2, barcode2, servicePointId).getId(); - // Printing request1 using user1 and assertRequest details - var printRequest = getPrintEvent(); - printRequest.put("requestIds", List.of(requestId1)); - printRequest.put("requesterId", userResource1.getId()); - - restAssuredClient.post(printRequest, printEventsUrl("/print-events-entry"), "post-print-event"); - - // Printing request2 using user2 and assertRequest details - printRequest = getPrintEvent(); - printRequest.put("requestIds", List.of(requestId2)); - printRequest.put("requesterId", userResource2.getId()); - - restAssuredClient.post(printRequest, printEventsUrl("/print-events-entry"), "post-print-event"); - JsonObject requestRepresentation1 = requestsClient.getMany(exactMatch("id", requestId1.toString())).getFirst(); - JsonObject requestRepresentation2 = requestsClient.getMany(exactMatch("id", requestId2.toString())).getFirst(); - assertRequestDetails(requestRepresentation1, requestId1, barcode1, servicePointId); - assertRequestDetails(requestRepresentation2, requestId2, barcode2, servicePointId); - assertThat("printDetails should not be null for request1 as the feature is enabled and the request is printed", - requestRepresentation1.getJsonObject("printDetails"), Matchers.notNullValue()); - assertThat("printDetails should not be null for request2 as the feature is enabled and the request is printed", - requestRepresentation2.getJsonObject("printDetails"), Matchers.notNullValue()); - assertPrintDetails(requestRepresentation1, 1, "2024-06-25T11:54:07.000Z", userResource1); - assertPrintDetails(requestRepresentation2, 1, "2024-06-25T11:54:07.000Z", userResource2); - - // printing both request for second time using user2 and assert requestDetails - printRequest.put("printEventDate", "2024-06-25T12:54:07.000Z"); - printRequest.put("requestIds", List.of(requestId1, requestId2)); - printRequest.put("requesterId", userResource2.getId()); - - restAssuredClient.post(printRequest, printEventsUrl("/print-events-entry"), "post-print-event"); - - requestRepresentation1 = requestsClient.getMany(exactMatch("id", requestId1.toString())).getFirst(); - requestRepresentation2 = requestsClient.getMany(exactMatch("id", requestId2.toString())).getFirst(); - assertRequestDetails(requestRepresentation1, requestId1, barcode1, servicePointId); - assertRequestDetails(requestRepresentation2, requestId2, barcode2, servicePointId); - assertPrintDetails(requestRepresentation1, 2, "2024-06-25T12:54:07.000Z", userResource2); - assertPrintDetails(requestRepresentation2, 2, "2024-06-25T12:54:07.000Z", userResource2); - - // printing request1 for third time using user1 and assert requestDetails - printRequest.put("printEventDate", "2024-06-25T12:58:07.000Z"); - printRequest.put("requestIds", List.of(requestId1)); - printRequest.put("requesterId", userResource1.getId()); - - restAssuredClient.post(printRequest, printEventsUrl("/print-events-entry"), "post-print-event"); - - requestRepresentation1 = requestsClient.getMany(exactMatch("id", requestId1.toString())).getFirst(); - requestRepresentation2 = requestsClient.getMany(exactMatch("id", requestId2.toString())).getFirst(); - assertRequestDetails(requestRepresentation1, requestId1, barcode1, servicePointId); - assertRequestDetails(requestRepresentation2, requestId2, barcode2, servicePointId); - assertPrintDetails(requestRepresentation1, 3, "2024-06-25T12:58:07.000Z", userResource1); - assertPrintDetails(requestRepresentation2, 2, "2024-06-25T12:54:07.000Z", userResource2); - } - - @Test - void printAndFetchRequestWithPrintEventFeatureDisabled() { - assertThat("Circulation settings enabled", circulationSettingsClient.getAll().isEmpty()); - var barcode1 = "barcode1"; - var barcode2 = "barcode2"; - // creating 2 different requests and print it - // assert request details without enabling printEvent feature - circulationSettingsClient.create(new CirculationSettingBuilder() - .withName("printEventLogFeature") - .withValue(new JsonObject().put("enablePrintLog", false))); - var userResource = usersFixture.charlotte(); - var servicePointId = servicePointsFixture.cd1().getId(); - var requestId1 = createRequest(userResource, barcode1, servicePointId).getId(); - var requestId2 = createRequest(userResource, barcode2, servicePointId).getId(); - var printRequest = getPrintEvent(); - printRequest.put("requestIds", List.of(requestId1, requestId2)); - - restAssuredClient.post(printRequest, printEventsUrl("/print-events-entry"), "post-print-event"); - - JsonObject requestRepresentation1 = requestsClient.getMany(exactMatch("id", requestId1.toString())).getFirst(); - JsonObject requestRepresentation2 = requestsClient.getMany(exactMatch("id", requestId2.toString())).getFirst(); - assertRequestDetails(requestRepresentation1, requestId1, barcode1, servicePointId); - assertRequestDetails(requestRepresentation2, requestId2, barcode2, servicePointId); - assertThat("printDetails should be null for request1 because the print event feature is disabled", - requestRepresentation1.getJsonObject("printDetails"), Matchers.nullValue()); - assertThat("printDetails should be null for request2 because the print event feature is disabled", - requestRepresentation2.getJsonObject("printDetails"), Matchers.nullValue()); - } - @Test void itemLevelRequestShouldBeCreatedWithDeliveryFulfillmentPreference() { final UUID requestPolicyId = UUID.randomUUID(); @@ -5350,52 +5232,4 @@ private void validateInstanceRepresentation(JsonObject requestInstance) { assertThat(firstPublication.getString("place"), is("New York")); assertThat(firstPublication.getString("dateOfPublication"), is("2016")); } - - private IndividualResource createRequest(UserResource userResource, String itemBarcode, - UUID pickupServicePointId) { - return requestsFixture.place( - new RequestBuilder() - .open() - .page() - .forItem(itemsFixture.basedUponSmallAngryPlanet(itemBarcode)) - .by(userResource) - .fulfillToHoldShelf() - .withRequestExpiration(LocalDate.of(2024, 7, 30)) - .withHoldShelfExpiration(LocalDate.of(2024, 8, 15)) - .withPickupServicePointId(pickupServicePointId)); - } - - private void assertRequestDetails(JsonObject representation, UUID id, String barcodeName, UUID servicePointId) { - assertThat(representation.getString("id"), is(id.toString())); - assertThat(representation.getString("requestType"), is("Page")); - assertThat(representation.getString("requestLevel"), is("Item")); - assertThat(representation.getString("requestDate"), is("2017-07-15T09:35:27.000Z")); - assertThat(representation.getJsonObject("item").getString("barcode"), is(barcodeName)); - assertThat(representation.getString("fulfillmentPreference"), is("Hold Shelf")); - assertThat(representation.getString("requestExpirationDate"), is("2024-07-30T23:59:59.000Z")); - assertThat(representation.getString("holdShelfExpirationDate"), is("2024-08-15")); - assertThat(representation.getString("status"), is("Open - Not yet filled")); - assertThat(representation.getString("pickupServicePointId"), is(servicePointId.toString())); - } - - private JsonObject getPrintEvent() { - return new JsonObject() - .put("requesterId", "5f5751b4-e352-4121-adca-204b0c2aec43") - .put("requesterName", "requester") - .put("printEventDate", "2024-06-25T11:54:07.000Z"); - } - - private void assertPrintDetails(JsonObject representation, int count, String printEventDate, - UserResource userResource) { - var printDetailObject = representation.getJsonObject("printDetails"); - var lastPrintRequesterObject = printDetailObject.getJsonObject("lastPrintRequester"); - assertThat(printDetailObject.getInteger("count"), is(count)); - assertThat(printDetailObject.getString("lastPrintedDate"), is(printEventDate)); - assertThat(lastPrintRequesterObject.getString("middleName"), - is(userResource.getJson().getJsonObject("personal").getString("middleName"))); - assertThat(lastPrintRequesterObject.getString("lastName"), - is(userResource.getJson().getJsonObject("personal").getString("lastName"))); - assertThat(lastPrintRequesterObject.getString("firstName"), - is(userResource.getJson().getJsonObject("personal").getString("firstName"))); - } } diff --git a/src/test/java/api/requests/RequestsAPIRetrievalTests.java b/src/test/java/api/requests/RequestsAPIRetrievalTests.java index 6605d72546..3c71fcc441 100644 --- a/src/test/java/api/requests/RequestsAPIRetrievalTests.java +++ b/src/test/java/api/requests/RequestsAPIRetrievalTests.java @@ -1,5 +1,24 @@ package api.requests; +import api.support.APITests; +import api.support.MultipleJsonRecords; +import api.support.builders.Address; +import api.support.builders.ItemBuilder; +import api.support.builders.RequestBuilder; +import api.support.http.IndividualResource; +import api.support.http.ItemResource; +import api.support.http.UserResource; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; +import org.folio.circulation.support.http.client.Response; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; + +import java.net.HttpURLConnection; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.UUID; + import static api.support.builders.ItemBuilder.CHECKED_OUT; import static api.support.fixtures.ConfigurationExample.newYorkTimezoneConfiguration; import static api.support.http.CqlQuery.noQuery; @@ -26,26 +45,6 @@ import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.net.HttpURLConnection; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.UUID; - -import org.folio.circulation.support.http.client.Response; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.Test; - -import api.support.APITests; -import api.support.MultipleJsonRecords; -import api.support.TlrFeatureStatus; -import api.support.builders.Address; -import api.support.builders.ItemBuilder; -import api.support.builders.RequestBuilder; -import api.support.http.IndividualResource; -import api.support.http.ItemResource; -import io.vertx.core.json.JsonArray; -import io.vertx.core.json.JsonObject; - class RequestsAPIRetrievalTests extends APITests { private static final String NEW_TAG = "new"; private static final String IMPORTANT_TAG = "important"; @@ -869,4 +868,54 @@ private void assertThatRequestsHavePatronComments(MultipleJsonRecords requests) hasJsonPath("patronComments", "Comment 5") )); } + + + @Test + void printDetailsTest() { + UserResource printDetailsRequester = usersFixture.charlotte(); + UUID printDetailsRequesterId = printDetailsRequester.getId(); + final IndividualResource smallAngryPlanet = itemsFixture.basedUponSmallAngryPlanet(); + final IndividualResource workAddressType = addressTypesFixture.work(); + final IndividualResource charlotte = usersFixture.charlotte( + builder -> builder.withAddress( + new Address(workAddressType.getId(), + "Fake first address line", + "Fake second address line", + "Fake city", + "Fake region", + "Fake postal code", + "Fake country code"))); + + requestsFixture.place(new RequestBuilder() + .page() + .forItem(smallAngryPlanet) + .deliverToAddress(workAddressType.getId()) + .by(charlotte) + .withPrintDetails(new RequestBuilder + .PrintDetails(49, printDetailsRequesterId.toString(), + true, "2024-09-16T11:58:22.295+00:00"))); + + final MultipleJsonRecords requests = requestsFixture.getRequests( + queryFromTemplate("printDetails.isPrinted==%s", "true"), + noLimit(), noOffset()); + + assertThat(requests.size(), is(1)); + assertThat(requests.totalRecords(), is(1)); + + JsonObject printDetails = requests.getFirst().getJsonObject("printDetails"); + assertThat(printDetails.getInteger("printCount"), is(49)); + assertThat(printDetails.getString("requesterId"), + is(printDetailsRequesterId.toString())); + assertTrue(printDetails.getBoolean("isPrinted")); + + JsonObject lastPrintRequester = printDetails.getJsonObject( + "lastPrintRequester"); + JsonObject expectedLastPrintRequester = printDetailsRequester.getJson() + .getJsonObject("personal"); + + assertThat(lastPrintRequester.getString("firstName"), + is(expectedLastPrintRequester.getString("firstName"))); + assertThat(lastPrintRequester.getString("lastName"), + is(expectedLastPrintRequester.getString("lastName"))); + } } diff --git a/src/test/java/api/support/builders/RequestBuilder.java b/src/test/java/api/support/builders/RequestBuilder.java index 2514482a1e..180de0a22b 100644 --- a/src/test/java/api/support/builders/RequestBuilder.java +++ b/src/test/java/api/support/builders/RequestBuilder.java @@ -63,6 +63,7 @@ public class RequestBuilder extends JsonBuilder implements Builder { private final Tags tags; private final String patronComments; private final BlockOverrides blockOverrides; + private final PrintDetails printDetails; public RequestBuilder() { this(UUID.randomUUID(), @@ -89,6 +90,7 @@ public RequestBuilder() { null, null, null, + null, null); } @@ -120,7 +122,8 @@ public static RequestBuilder from(IndividualResource response) { getUUIDProperty(representation, "pickupServicePointId"), new Tags((toStream(representation.getJsonObject("tags"), "tagList").collect(toList()))), getProperty(representation, "patronComments"), - null + null, + PrintDetails.fromRepresentation(representation) ); } @@ -191,6 +194,10 @@ public JsonObject create() { } } + if (printDetails != null) { + put(request, "printDetails", printDetails.toJsonObject()); + } + return request; } @@ -321,4 +328,35 @@ private static class PatronSummary { public static class Tags { private final List tagList; } + + @AllArgsConstructor + @Getter + public static class PrintDetails { + private final Integer printCount; + private final String requesterId; + private final Boolean isPrinted; + private final String printEventDate; + + public static PrintDetails fromRepresentation(JsonObject representation) { + JsonObject printDetails = representation.getJsonObject("printDetails"); + if (printDetails != null) { + final Integer printCount = printDetails.getInteger("printCount"); + final String requesterId = printDetails.getString("requesterId"); + final Boolean isPrinted = printDetails.getBoolean("isPrinted"); + final String printEventDate = printDetails.getString("printEventDate"); + return new PrintDetails(printCount, requesterId, isPrinted, + printEventDate); + } + return null; + } + + public JsonObject toJsonObject() { + JsonObject printDetails = new JsonObject(); + printDetails.put("printCount", printCount); + printDetails.put("requesterId", requesterId); + printDetails.put("isPrinted", isPrinted); + printDetails.put("printEventDate", printEventDate); + return printDetails; + } + } } diff --git a/src/test/java/api/support/fakes/FakeOkapi.java b/src/test/java/api/support/fakes/FakeOkapi.java index c146982ce8..1ed5b8f5b0 100644 --- a/src/test/java/api/support/fakes/FakeOkapi.java +++ b/src/test/java/api/support/fakes/FakeOkapi.java @@ -427,8 +427,6 @@ public void start(Promise startFuture) throws IOException { .withChangeMetadata() .create().register(router); - new FakePrintEventStatusModule().register(router); - new FakeFeeFineOperationsModule().register(router); server.requestHandler(router) diff --git a/src/test/java/api/support/fakes/FakePrintEventStatusModule.java b/src/test/java/api/support/fakes/FakePrintEventStatusModule.java deleted file mode 100644 index aaeced3434..0000000000 --- a/src/test/java/api/support/fakes/FakePrintEventStatusModule.java +++ /dev/null @@ -1,83 +0,0 @@ -package api.support.fakes; - -import io.vertx.core.buffer.Buffer; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.RoutingContext; -import lombok.SneakyThrows; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import static api.support.APITestContext.getTenantId; -import static api.support.fakes.Storage.getStorage; -import static org.folio.HttpStatus.HTTP_UNPROCESSABLE_ENTITY; -import static org.folio.circulation.support.http.server.JsonHttpResponse.ok; - -public class FakePrintEventStatusModule { - - @SneakyThrows - public void register(Router router) { - router.post("/print-events-storage/print-events-status") - .handler(this::handlePrintEventStatusRequest); - } - - private void handlePrintEventStatusRequest(RoutingContext routingContext) { - var request = routingContext.body().asJsonObject(); - var requestIds = request.getJsonArray("requestIds"); - if (requestIds.isEmpty()) { - Buffer buffer = Buffer.buffer( - "size must be between 1 and 2147483647", "UTF-8"); - routingContext.response() - .setStatusCode(HTTP_UNPROCESSABLE_ENTITY.toInt()) - .putHeader("content-type", "text/plain; charset=utf-8") - .putHeader("content-length", Integer.toString(buffer.length())) - .write(buffer); - routingContext.response().end(); - } else { - var jsonObjectList = new ArrayList<>(getStorage() - .getTenantResources("/print-events-storage/print-events-entry", getTenantId()) - .values() - .stream() - .toList()); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); - // Sorting jsonObjectList based on PrintEventDate so that it will always return latest printEventDetail - jsonObjectList.sort((obj1, obj2) -> { - try { - Date date1 = dateFormat.parse(obj1.getString("printEventDate")); - Date date2 = dateFormat.parse(obj2.getString("printEventDate")); - return date2.compareTo(date1); - } catch (ParseException e) { - throw new RuntimeException(e); - } - }); - Map> groupByRequestIdMap = new LinkedHashMap<>(); - requestIds.forEach(requestId -> { - var requestList = jsonObjectList.stream().filter(jsonObject -> - jsonObject.getJsonArray("requestIds").contains(requestId)) - .toList(); - groupByRequestIdMap.put((String) requestId, requestList); - }); - var jsonObjectResponse = new JsonObject(); - var printEventStatusResponses = new ArrayList<>(); - jsonObjectResponse.put("printEventsStatusResponses", printEventStatusResponses); - requestIds.forEach(id -> { - var requestDetail = groupByRequestIdMap.get(id); - if (requestDetail != null && !requestDetail.isEmpty()) { - var object = new JsonObject() - .put("requestId", id) - .put("count", requestDetail.size()) - .put("requesterId", requestDetail.get(0).getString("requesterId")) - .put("printEventDate", requestDetail.get(0).getString("printEventDate")); - printEventStatusResponses.add(object); - } - }); - ok(jsonObjectResponse).writeTo(routingContext.response()); - } - } -} diff --git a/src/test/java/api/support/fakes/FakeStorageModule.java b/src/test/java/api/support/fakes/FakeStorageModule.java index a3cf6cdff1..2224d6b95a 100644 --- a/src/test/java/api/support/fakes/FakeStorageModule.java +++ b/src/test/java/api/support/fakes/FakeStorageModule.java @@ -390,7 +390,9 @@ private void getMany(RoutingContext routingContext) { result.put(collectionPropertyName, new JsonArray(pagedItems)); result.put("totalRecords", filteredItems.size()); - + if(collectionPropertyName.equalsIgnoreCase("requests")) { + System.out.println(); + } log.debug("Found {} resources: {}", recordTypeName, result.encodePrettily()); HttpServerResponse response = routingContext.response();