Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,20 @@
"circulation.renew-loan.all"
]
},
{
"methods": [
"POST"
],
"pathPattern": "/circulation/pickup-by-barcode-for-use-at-location",
"permissionsRequired": []
},
{
"methods": [
"POST"
],
"pathPattern": "/circulation/hold-by-barcode-for-use-at-location",
"permissionsRequired": []
},
{
"methods": [
"GET"
Expand Down
13 changes: 13 additions & 0 deletions ramls/examples/at-location-usage-status-change-error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"errors": [
{
"message": "TBD",
"parameters": [
{
"key": "itemId",
"value": "91719676-e7b5-4f83-bdab-cb70dd10c1e3"
}
]
}
]
}
62 changes: 62 additions & 0 deletions ramls/for-use-at-location-shelf.raml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#%RAML 1.0
title: Change usage status of items to be used at location (ie reading room)
version: v0.1
protocols: [ HTTP, HTTPS ]
baseUri: http://localhost:9130

documentation:
- title: API for changing usage status of items used at location
content: <b>Change usage status API</b>

types:
errors: !include raml-util/schemas/errors.schema

traits:
validate: !include raml-util/traits/validation.raml

/circulation:
/hold-by-barcode-for-use-at-location:
post:
is: [validate]
body:
application/json:
type: !include hold-for-use-at-location-request.json
responses:
200:
description: "The at-location usage status of the loaned item set to held"
422:
description: "Unable to change the usage status for the loan"
body:
application/json:
type: errors
example: !include examples/at-location-usage-status-change-error.json
404:
description: "The loan is not found"
500:
description: "Internal server error, e.g. due to misconfiguration"
body:
text/plain:
example: "Internal server error, contact administrator"

/pickup-by-barcode-for-use-at-location:
post:
is: [validate]
body:
application/json:
type: !include pickup-for-use-at-location-request.json
responses:
200:
description: "The at-location usage status of the loaned item set to in-use"
422:
description: "Unable to change the usage status for the loan"
body:
application/json:
type: errors
example: !include examples/at-location-usage-status-change-error.json
404:
description: "The loan is not found"
500:
description: "Internal server error, e.g. due to misconfiguration"
body:
text/plain:
example: "Internal server error, contact administrator"
14 changes: 14 additions & 0 deletions ramls/hold-for-use-at-location-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"description": "Request to switch status of use at location to 'Held'",
"properties": {
"itemBarcode": {
"description": "Barcode of the item being in use at location",
"type": "string"
}
},
"required": [
"itemBarcode"
]
}
20 changes: 20 additions & 0 deletions ramls/loan.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,26 @@
}
}
},
"forUseAtLocation": {
"description": "Status of loan/item that is to be used in the library",
"type": "object",
"properties": {
"status": {
"description": "Indicates if the item is currently used by or being held for the patron",
"type": "string",
"enum": [
"In use",
"Held",
"Returned"
]
},
"statusDate": {
"description": "Date and time the status was registered",
"type": "string",
"format": "date-time"
}
}
},
"loanDate": {
"description": "Date and time when the loan began",
"type": "string",
Expand Down
19 changes: 19 additions & 0 deletions ramls/pickup-for-use-at-location-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"description": "Request to switch status of use at location to 'In use'",
"properties": {
"itemBarcode": {
"description": "Barcode of the item lent to the patron for use at location",
"type": "string"
},
"userBarcode": {
"description": "Barcode of the user (representing the patron)",
"type": "string"
}
},
"required": [
"itemBarcode",
"userBarcode"
]
}
14 changes: 14 additions & 0 deletions ramls/put-on-hold-for-use-at-location.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"description": "Request to switch status of use at location to 'Held'",
"properties": {
"itemBarcode": {
"description": "Barcode of the item lent to the patron for use at location",
"type": "string"
}
},
"required": [
"itemBarcode"
]
}
5 changes: 4 additions & 1 deletion src/main/java/org/folio/circulation/CirculationVerticle.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
import org.folio.circulation.resources.handlers.LoanRelatedFeeFineClosedHandlerResource;
import org.folio.circulation.resources.renewal.RenewByBarcodeResource;
import org.folio.circulation.resources.renewal.RenewByIdResource;
import org.folio.circulation.resources.foruseatlocation.HoldByBarcodeResource;
import org.folio.circulation.resources.foruseatlocation.PickUpByBarcodeResource;
import org.folio.circulation.support.logging.LogHelper;
import org.folio.circulation.support.logging.Logging;

Expand Down Expand Up @@ -97,7 +99,8 @@ public void start(Promise<Void> startFuture) {

new RenewByBarcodeResource(client).register(router);
new RenewByIdResource(client).register(router);

new HoldByBarcodeResource(client).register(router);
new PickUpByBarcodeResource(client).register(router);
new AllowedServicePointsResource(client).register(router);
new LoanCollectionResource(client).register(router);
new RequestCollectionResource(client).register(router);
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/folio/circulation/domain/EventType.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ public enum EventType {
LOAN_DUE_DATE_CHANGED,
LOAN_CLOSED,
LOG_RECORD,
LOAN_RELATED_FEE_FINE_CLOSED
LOAN_RELATED_FEE_FINE_CLOSED,
ITEM_HELD_FOR_USE_AT_LOCATION,
ITEM_PICKED_UP_FOR_USE_AT_LOCATION
}
14 changes: 13 additions & 1 deletion src/main/java/org/folio/circulation/domain/Loan.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import static org.folio.circulation.domain.representations.LoanProperties.ACTION_COMMENT;
import static org.folio.circulation.domain.representations.LoanProperties.AGED_TO_LOST_DATE;
import static org.folio.circulation.domain.representations.LoanProperties.AGED_TO_LOST_DELAYED_BILLING;
import static org.folio.circulation.domain.representations.LoanProperties.AT_LOCATION_USE_STATUS;
import static org.folio.circulation.domain.representations.LoanProperties.AT_LOCATION_USE_STATUS_DATE;
import static org.folio.circulation.domain.representations.LoanProperties.BILL_DATE;
import static org.folio.circulation.domain.representations.LoanProperties.BILL_NUMBER;
import static org.folio.circulation.domain.representations.LoanProperties.CHECKIN_SERVICE_POINT_ID;
Expand All @@ -30,6 +32,7 @@
import static org.folio.circulation.domain.representations.LoanProperties.DATE_LOST_ITEM_SHOULD_BE_BILLED;
import static org.folio.circulation.domain.representations.LoanProperties.DECLARED_LOST_DATE;
import static org.folio.circulation.domain.representations.LoanProperties.DUE_DATE;
import static org.folio.circulation.domain.representations.LoanProperties.FOR_USE_AT_LOCATION;
import static org.folio.circulation.domain.representations.LoanProperties.ITEM_LOCATION_ID_AT_CHECKOUT;
import static org.folio.circulation.domain.representations.LoanProperties.ITEM_STATUS;
import static org.folio.circulation.domain.representations.LoanProperties.LAST_FEE_BILLED;
Expand Down Expand Up @@ -207,6 +210,16 @@ public String getAction() {
return getProperty(representation, ACTION);
}

public Loan changeStatusOfUsageAtLocation(String usageStatus) {
writeByPath(representation, usageStatus, FOR_USE_AT_LOCATION, AT_LOCATION_USE_STATUS);
writeByPath(representation, ClockUtil.getZonedDateTime().toString(), FOR_USE_AT_LOCATION, AT_LOCATION_USE_STATUS_DATE);
return this;
}

public boolean isForUseAtLocation() {
return representation.containsKey(FOR_USE_AT_LOCATION);
}

private void changeCheckInServicePointId(UUID servicePointId) {
log.debug("changeCheckInServicePointId:: parameters servicePointId: {}", servicePointId);
write(representation, "checkinServicePointId", servicePointId);
Expand Down Expand Up @@ -736,7 +749,6 @@ private void changeClaimedReturnedDate(ZonedDateTime claimedReturnedDate) {
public Loan closeLoan(LoanAction action) {
log.debug("closeLoan:: parameters action: {}", action);
changeStatus(LoanStatus.CLOSED);

changeAction(action);
removeActionComment();

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/folio/circulation/domain/LoanAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public enum LoanAction {
STAFF_INFO_ADDED("staffInfoAdded"),
RESOLVE_CLAIM_AS_RETURNED_BY_PATRON("checkedInReturnedByPatron"),
RESOLVE_CLAIM_AS_FOUND_BY_LIBRARY("checkedInFoundByLibrary"),

REMINDER_FEE("reminderFee");

REMINDER_FEE("reminderFee"),
HELD_FOR_USE_AT_LOCATION("heldForUseAtLocation"),
PICKED_UP_FOR_USE_AT_LOCATION ("pickedUpForUseAtLocation");
private final String value;

LoanAction(String value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public Result<Loan> checkIn(Loan loan, ZonedDateTime systemDateTime,
loan.removeAgedToLostBillingInfo();
}

if (loan.isForUseAtLocation()) {
loan.changeStatusOfUsageAtLocation("Returned");
}

return succeeded(loan.checkIn(request.getCheckInDate(), systemDateTime,
request.getServicePointId()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class LoanPolicy extends Policy {
private static final String ALTERNATE_RENEWAL_LOAN_PERIOD_KEY = "alternateRenewalLoanPeriod";
private static final String ALLOW_RECALLS_TO_EXTEND_OVERDUE_LOANS = "allowRecallsToExtendOverdueLoans";
private static final String ALTERNATE_RECALL_RETURN_INTERVAL = "alternateRecallReturnInterval";
private static final String FOR_USE_AT_LOCATION = "forUseAtLocation";

private static final String INTERVAL_ID = "intervalId";
private static final String DURATION = "duration";
Expand Down Expand Up @@ -345,6 +346,10 @@ public boolean isNotLoanable() {
return !isLoanable();
}

public boolean isForUseAtLocation() {
return getBooleanProperty(getLoansPolicy(), FOR_USE_AT_LOCATION);
}

public DueDateManagement getDueDateManagement() {
JsonObject loansPolicyObj = getLoansPolicy();
if (Objects.isNull(loansPolicyObj)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ private LoanProperties() { }
public static final String DATE_LOST_ITEM_SHOULD_BE_BILLED = "dateLostItemShouldBeBilled";
public static final String METADATA = "metadata";
public static final String UPDATED_BY_USER_ID = "updatedByUserId";
public static final String FOR_USE_AT_LOCATION = "forUseAtLocation";
public static final String AT_LOCATION_USE_STATUS = "status";
public static final String AT_LOCATION_USE_STATUS_DATE = "statusDate";
public static final String USAGE_STATUS_IN_USE = "In use";
public static final String USAGE_STATUS_HELD = "Held";
public static final String USAGE_STATUS_RETURNED = "Returned";
public static final String CREATED_DATE = "createdDate";

public static final String REMINDERS = "reminders";
public static final String LAST_FEE_BILLED = "lastFeeBilled";
public static final String BILL_NUMBER = "number";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import static org.folio.circulation.domain.LoanAction.CLOSED_LOAN;
import static org.folio.circulation.domain.LoanAction.DECLARED_LOST;
import static org.folio.circulation.domain.LoanAction.DUE_DATE_CHANGED;
import static org.folio.circulation.domain.LoanAction.HELD_FOR_USE_AT_LOCATION;
import static org.folio.circulation.domain.LoanAction.ITEM_AGED_TO_LOST;
import static org.folio.circulation.domain.LoanAction.MISSING;
import static org.folio.circulation.domain.LoanAction.PICKED_UP_FOR_USE_AT_LOCATION;
import static org.folio.circulation.domain.LoanAction.RECALLREQUESTED;
import static org.folio.circulation.domain.LoanAction.RENEWED;
import static org.folio.circulation.domain.LoanAction.RENEWED_THROUGH_OVERRIDE;
Expand Down Expand Up @@ -39,6 +41,8 @@ public class LogContextActionResolver {
loanLogActions.put(DUE_DATE_CHANGED.getValue(), "Changed due date");
loanLogActions.put(PATRON_INFO_ADDED.getValue(), "Patron info added");
loanLogActions.put(STAFF_INFO_ADDED.getValue(), "Staff info added");
loanLogActions.put(HELD_FOR_USE_AT_LOCATION.getValue(),"Held for use at location");
loanLogActions.put(PICKED_UP_FOR_USE_AT_LOCATION.getValue(), "Picked up for use at location");
}

public static String resolveAction(String action) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ public enum LogEventType {
REQUEST_CREATED_THROUGH_OVERRIDE("REQUEST_CREATED_THROUGH_OVERRIDE_EVENT"),
REQUEST_UPDATED("REQUEST_UPDATED_EVENT"),
REQUEST_MOVED("REQUEST_MOVED_EVENT"),
REQUEST_REORDERED("REQUEST_REORDERED_EVENT");
REQUEST_REORDERED("REQUEST_REORDERED_EVENT"),
HELD_FOR_USE_AT_LOCATION("HELD_FOR_USE_AT_LOCATION_EVENT"),
PICKED_UP_FOR_USE_AT_LOCATION("PICKED_UP_FOR_USE_AT_LOCATION_EVENT");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ private void checkIn(RoutingContext routingContext) {
processAdapter::findSingleOpenLoan, CheckInContext::withLoan))
.thenComposeAsync(findLoanResult -> findLoanResult.combineAfter(
processAdapter::checkInLoan, CheckInContext::withLoan))
.thenApply(r -> r.map(processAdapter::markReturnedIfForUseAtLocation))
.thenComposeAsync(checkInLoan -> checkInLoan.combineAfter(
processAdapter::updateRequestQueue, CheckInContext::withRequestQueue))
.thenComposeAsync(r -> r.after(processAdapter::findFulfillableRequest))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.folio.circulation.resources;

import static java.util.concurrent.CompletableFuture.completedFuture;
import static org.folio.circulation.domain.representations.LoanProperties.USAGE_STATUS_RETURNED;
import static org.folio.circulation.support.results.Result.succeeded;

import java.lang.invoke.MethodHandles;
Expand Down Expand Up @@ -274,6 +275,14 @@ CheckInContext setInHouseUse(CheckInContext checkInContext) {
checkInContext.getCheckInRequest()));
}

CheckInContext markReturnedIfForUseAtLocation(CheckInContext checkInContext) {
Loan loan = checkInContext.getLoan();
if (loan != null && loan.isForUseAtLocation()) {
loan.changeStatusOfUsageAtLocation(USAGE_STATUS_RETURNED);
}
return checkInContext;
}

public CompletableFuture<Result<CheckInContext>> logCheckInOperation(
CheckInContext checkInContext) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static java.util.concurrent.CompletableFuture.completedFuture;
import static org.folio.circulation.domain.ItemStatus.CHECKED_OUT;
import static org.folio.circulation.domain.LoanAction.CHECKED_OUT_THROUGH_OVERRIDE;
import static org.folio.circulation.domain.representations.LoanProperties.USAGE_STATUS_IN_USE;
import static org.folio.circulation.resources.handlers.error.CirculationErrorType.FAILED_TO_FETCH_ITEM;
import static org.folio.circulation.resources.handlers.error.CirculationErrorType.FAILED_TO_FETCH_PROXY_USER;
import static org.folio.circulation.resources.handlers.error.CirculationErrorType.FAILED_TO_FETCH_USER;
Expand Down Expand Up @@ -178,6 +179,7 @@ CompletableFuture<Result<LoanAndRelatedRecords>> checkOut(CheckOutByBarcodeReque
.thenApply(r -> r.next(this::setItemLocationIdAtCheckout))
.thenComposeAsync(r -> r.after(records -> checkOut(records, clients)))
.thenApply(r -> r.map(this::checkOutItem))
.thenApply(r -> r.map(this::markInUseIfForUseAtLocation))
.thenCompose(r -> r.after(l -> acquireLockIfNeededOrFail(settingsRepository,
checkOutLockRepository, l, checkOutLockId, validators, errorHandler)))
.thenComposeAsync(r -> r.after(requestQueueUpdate::onCheckOut))
Expand Down Expand Up @@ -305,6 +307,14 @@ private LoanAndRelatedRecords checkOutItem(LoanAndRelatedRecords loanAndRelatedR
return loanAndRelatedRecords.changeItemStatus(CHECKED_OUT);
}

private LoanAndRelatedRecords markInUseIfForUseAtLocation(LoanAndRelatedRecords loanAndRelatedRecords) {
Loan loan = loanAndRelatedRecords.getLoan();
if (loan.getLoanPolicy().isForUseAtLocation()) {
loan.changeStatusOfUsageAtLocation(USAGE_STATUS_IN_USE);
}
return loanAndRelatedRecords;
}

private Result<HttpResponse> createdLoanFrom(Result<JsonObject> result,
CirculationErrorHandler errorHandler) {

Expand Down
Loading