Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CIRC-2136 support floating collections #1505

Merged
merged 23 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6bdf704
add ID dev workflows
funkymalc Aug 22, 2024
f56ee44
Enable verbose debug both okclient and its curl DEVOPS-3370
dcrossleyau Aug 23, 2024
d589efa
Disable verbose okclient
dcrossleyau Aug 23, 2024
086c70a
update kubectl action
funkymalc Aug 28, 2024
20b18fa
Merge branch 'deployment' of ssh://github.com/indexdata/mod-circulati…
funkymalc Aug 28, 2024
bf8f964
CIRC-2136 Add support for floating collections
nielserik Aug 28, 2024
fe25a60
Merge pull request #1 from indexdata/CIRC-2136-floating-collections
nielserik Aug 28, 2024
e70f55b
CIRC-2141 Allow specifying item location when creating title-level re…
JanisSaldabols Sep 6, 2024
cbf3abd
CIRC-2141 Add new field to request schema
JanisSaldabols Sep 11, 2024
3436b21
Merge pull request #2 from indexdata/CIRC-2141
JanisSaldabols Sep 17, 2024
261420d
CIRC-2136 fix for npe in check for floating
nielserik Sep 23, 2024
728ddea
Merge branch 'master' into CIRC-2136-floating-collections
nielserik Sep 23, 2024
0f90cd9
Merge pull request #3 from indexdata/CIRC-2136-floating-collections
nielserik Sep 23, 2024
396acd0
CIRC-2136 fix query limit, locations-by-service-point look-up
nielserik Oct 16, 2024
4b1964b
Merge remote-tracking branch 'origin/CIRC-2136-floating-collections' …
nielserik Oct 16, 2024
f155f2c
Merge pull request #4 from indexdata/CIRC-2136-floating-collections
nielserik Oct 16, 2024
e98235b
CIRC-2136 set new location on check-in response and pick slip context.
nielserik Oct 24, 2024
117459c
Merge pull request #6 from indexdata/CIRC-2136-floating-collections
nielserik Oct 24, 2024
a2d1546
Merge branch 'master' into CIRC-2136-floating-collections
nielserik Oct 30, 2024
91d0970
CIRC-2136 set a new location in check-in response, pick slip only if …
nielserik Oct 31, 2024
5a876ca
Merge remote-tracking branch 'origin/CIRC-2136-floating-collections' …
nielserik Oct 31, 2024
6ec2a58
Merge branch 'deployment' into CIRC-2136-floating-collections
nielserik Oct 31, 2024
0796048
CIRC-2136 remove spurious workflows
nielserik Oct 31, 2024
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
49 changes: 40 additions & 9 deletions src/main/java/org/folio/circulation/domain/Item.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public class Item {
@Getter
private final String shelvingOrder;
@NonNull private final Location permanentLocation;

@Getter
private final Location floatDestinationLocation;
private final ServicePoint inTransitDestinationServicePoint;

private boolean changed;
Expand All @@ -57,7 +60,7 @@ public static Item from(JsonObject representation) {
}
public Item(String id, JsonObject itemRepresentation, Location effectiveLocation,
LastCheckIn lastCheckIn, CallNumberComponents callNumberComponents,
String shelvingOrder, Location permanentLocation,
String shelvingOrder, Location permanentLocation, Location floatDestinationLocation,
ServicePoint inTransitDestinationServicePoint, boolean changed,
Holdings holdings, Instance instance, MaterialType materialType,
LoanType loanType, ItemDescription description) {
Expand All @@ -69,6 +72,7 @@ public Item(String id, JsonObject itemRepresentation, Location effectiveLocation
this.callNumberComponents = callNumberComponents;
this.shelvingOrder = shelvingOrder;
this.permanentLocation = permanentLocation;
this.floatDestinationLocation = floatDestinationLocation;
this.inTransitDestinationServicePoint = inTransitDestinationServicePoint;
this.changed = changed;
this.holdings = holdings;
Expand Down Expand Up @@ -348,59 +352,86 @@ public String getPermanentLocationId() {
return firstNonBlank(permanentLocation.getId(), holdings.getPermanentLocationId());
}

public String getFloatDestinationLocationId() {
return floatDestinationLocation != null ? floatDestinationLocation.getId() : null;
}

public boolean canFloatThroughCheckInServicePoint() {
return getLocation() != null
&& getLocation().isFloatingCollection()
&& getFloatDestinationLocation() != null
&& getFloatDestinationLocation().getId() != null;
}

public Item withLocation(Location newLocation) {
return new Item(this.id, this.itemRepresentation, newLocation,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, this.inTransitDestinationServicePoint, this.changed,
this.permanentLocation, this.floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
this.holdings, this.instance, this.materialType, this.loanType, description);
}

public Item withMaterialType(@NonNull MaterialType materialType) {
return new Item(this.id, this.itemRepresentation, this.location,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, this.inTransitDestinationServicePoint, this.changed,
this.permanentLocation, this.floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
this.holdings, this.instance, materialType, this.loanType, this.description);
}

public Item withHoldings(@NonNull Holdings holdings) {
return new Item(this.id, this.itemRepresentation, this.location,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, this.inTransitDestinationServicePoint, this.changed,
this.permanentLocation, this.floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
holdings, this.instance, this.materialType, this.loanType, this.description);
}

public Item withInstance(@NonNull Instance instance) {
return new Item(this.id, this.itemRepresentation, this.location,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, this.inTransitDestinationServicePoint, this.changed,
this.permanentLocation, this.floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
this.holdings, instance, this.materialType, this.loanType, this.description);
}

public Item withLoanType(@NonNull LoanType loanType) {
return new Item(this.id, this.itemRepresentation, this.location,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, this.inTransitDestinationServicePoint, this.changed,
this.permanentLocation, this.floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
this.holdings, this.instance, this.materialType, loanType, this.description);
}

public Item withLastCheckIn(@NonNull LastCheckIn lastCheckIn) {
return new Item(this.id, this.itemRepresentation, this.location,
lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, this.inTransitDestinationServicePoint, this.changed,
this.permanentLocation, this.floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
this.holdings, this.instance, this.materialType, this.loanType, this.description);
}

public Item withPermanentLocation(Location permanentLocation) {
return new Item(this.id, this.itemRepresentation, this.location,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
permanentLocation, this.inTransitDestinationServicePoint, this.changed,
permanentLocation, this.floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
this.holdings, this.instance, this.materialType, this.loanType, this.description);
}

public Item withFloatDestinationLocation(Location floatDestinationLocation) {
return new Item(this.id, this.itemRepresentation, this.location,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, floatDestinationLocation,
this.inTransitDestinationServicePoint, this.changed,
this.holdings, this.instance, this.materialType, this.loanType, this.description);
}

public Item withInTransitDestinationServicePoint(ServicePoint servicePoint) {
return new Item(this.id, this.itemRepresentation, this.location,
this.lastCheckIn, this.callNumberComponents, this.shelvingOrder,
this.permanentLocation, servicePoint, this.changed, this.holdings,
this.permanentLocation, this.floatDestinationLocation,
servicePoint, this.changed, this.holdings,
this.instance, this.materialType, this.loanType, this.description);
}

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/folio/circulation/domain/Location.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class Location {
String discoveryDisplayName;
@NonNull Collection<UUID> servicePointIds;
UUID primaryServicePointId;
Boolean isFloatingCollection;
@NonNull Institution institution;
@NonNull Campus campus;
@NonNull Library library;
Expand All @@ -27,6 +28,7 @@ public static Location unknown() {

public static Location unknown(String id) {
return new Location(id, null, null, null, List.of(), null,
false,
Institution.unknown(null), Campus.unknown(null), Library.unknown(null),
ServicePoint.unknown());
}
Expand Down Expand Up @@ -85,23 +87,31 @@ public ServicePoint getPrimaryServicePoint() {
return primaryServicePoint;
}

public boolean isFloatingCollection() {
return isFloatingCollection;
}

public Location withInstitution(Institution institution) {
return new Location(id, name, code, discoveryDisplayName, servicePointIds, primaryServicePointId,
isFloatingCollection,
institution, campus, library, primaryServicePoint);
}

public Location withCampus(Campus campus) {
return new Location(id, name, code, discoveryDisplayName, servicePointIds, primaryServicePointId,
isFloatingCollection,
institution, campus, library, primaryServicePoint);
}

public Location withLibrary(Library library) {
return new Location(id, name, code, discoveryDisplayName, servicePointIds, primaryServicePointId,
isFloatingCollection,
institution, campus, library, primaryServicePoint);
}

public Location withPrimaryServicePoint(ServicePoint servicePoint) {
return new Location(id, name, code, discoveryDisplayName, servicePointIds, primaryServicePointId,
isFloatingCollection,
institution, campus, library, servicePoint);
}

Expand Down
7 changes: 4 additions & 3 deletions src/main/java/org/folio/circulation/domain/UpdateItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ private Result<Item> changeItemOnCheckIn(Item item, Request request, UUID checkI
return changeItemWithOutstandingRequest(item, request, checkInServicePointId);
} else {
if(Optional.ofNullable(item.getLocation())
.map(location -> location.homeLocationIsServedBy(checkInServicePointId))
.map(location ->
location.homeLocationIsServedBy(checkInServicePointId)
|| (item.canFloatThroughCheckInServicePoint()))
.orElse(false)) {
return succeeded(item.available());
}
else {
} else {
return succeeded(item.inTransitToHome());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.folio.circulation.domain.FeeFineAction;
import org.folio.circulation.domain.Instance;
import org.folio.circulation.domain.Item;
import org.folio.circulation.domain.ItemStatus;
import org.folio.circulation.domain.Loan;
import org.folio.circulation.domain.Location;
import org.folio.circulation.domain.Request;
Expand Down Expand Up @@ -213,7 +214,8 @@ private static JsonObject createItemContext(Item item) {
.put("displaySummary", item.getDisplaySummary())
.put("descriptionOfPieces", item.getDescriptionOfPieces());

Location location = item.getLocation();
Location location = (item.canFloatThroughCheckInServicePoint() && item.isInStatus(ItemStatus.AVAILABLE)) ?
item.getFloatDestinationLocation() : item.getLocation();

if (location != null) {
log.info("createItemContext:: location is not null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.circulation.domain.Item;
import org.folio.circulation.domain.ItemStatus;
import org.folio.circulation.domain.Location;
import org.folio.circulation.domain.ServicePoint;

Expand Down Expand Up @@ -78,7 +79,10 @@ public JsonObject createItemSummary(Item item) {

final Location location = item.getLocation();

if (location != null) {
if (item.canFloatThroughCheckInServicePoint() && item.isInStatus(ItemStatus.AVAILABLE)) {
itemSummary.put("location", new JsonObject()
.put("name", item.getFloatDestinationLocation().getName()));
} else if (location != null) {
log.info("createItemSummary:: location is not null");
itemSummary.put("location", new JsonObject()
.put("name", location.getName()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static java.util.concurrent.CompletableFuture.supplyAsync;
import static java.util.function.Function.identity;
import static org.folio.circulation.domain.ItemStatus.AVAILABLE;
import static org.folio.circulation.domain.ItemStatus.IN_TRANSIT;
import static org.folio.circulation.domain.MultipleRecords.CombinationMatchers.matchRecordsById;
import static org.folio.circulation.domain.representations.ItemProperties.LAST_CHECK_IN;
import static org.folio.circulation.domain.representations.ItemProperties.STATUS_PROPERTY;
Expand Down Expand Up @@ -91,6 +92,7 @@ public CompletableFuture<Result<Item>> updateItem(Item item) {
log.debug("updateItem:: parameters item: {}", item);

final String IN_TRANSIT_DESTINATION_SERVICE_POINT_ID = "inTransitDestinationServicePointId";
final String TEMPORARY_LOCATION_ID = "temporaryLocationId";

if (item == null) {
log.info("updateItem:: item is null");
Expand All @@ -108,8 +110,14 @@ public CompletableFuture<Result<Item>> updateItem(Item item) {
new JsonObject().put("name", item.getStatus().getValue()));

remove(updatedItemRepresentation, IN_TRANSIT_DESTINATION_SERVICE_POINT_ID);
write(updatedItemRepresentation, IN_TRANSIT_DESTINATION_SERVICE_POINT_ID,
item.getInTransitDestinationServicePointId());
if (item.isInStatus(IN_TRANSIT)) {
write(updatedItemRepresentation, IN_TRANSIT_DESTINATION_SERVICE_POINT_ID,
item.getInTransitDestinationServicePointId());
} else if (item.isInStatus(AVAILABLE) && item.canFloatThroughCheckInServicePoint()) {
remove(updatedItemRepresentation, TEMPORARY_LOCATION_ID);
write(updatedItemRepresentation, TEMPORARY_LOCATION_ID,
item.getFloatDestinationLocationId());
}

final var lastCheckIn = item.getLastCheckIn();

Expand Down Expand Up @@ -176,7 +184,8 @@ private CompletableFuture<Result<MultipleRecords<Item>>> fetchLocations(
return result.combineAfter(this::fetchLocations,
(items, locations) -> items
.combineRecords(locations, Item::getPermanentLocationId, Item::withPermanentLocation, null)
.combineRecords(locations, Item::getEffectiveLocationId, Item::withLocation, null));
.combineRecords(locations, Item::getEffectiveLocationId, Item::withLocation, null)
.combineRecords(locations, Item::getFloatDestinationLocationId, Item::withFloatDestinationLocation, null));
}

private CompletableFuture<Result<Map<String, Location>>> fetchLocations(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.folio.circulation.support.SingleRecordFetcher;
import org.folio.circulation.support.fetching.CqlQueryFinder;
import org.folio.circulation.support.http.client.CqlQuery;
import org.folio.circulation.support.http.client.PageLimit;
import org.folio.circulation.support.results.Result;

public class LocationRepository {
Expand Down Expand Up @@ -87,6 +88,11 @@ public CompletableFuture<Result<Location>> getPermanentLocation(Item item) {
return getLocation(item, Item::getPermanentLocationId);
}

public CompletableFuture<Result<Location>> getFloatDestinationLocation(Item item) {
log.debug("getFloatDestinationLocation:: parameters item: {}", item);
return getLocation(item, Item::getFloatDestinationLocationId);
}

private CompletableFuture<Result<Location>> getLocation(Item item,
Function<Item, String> locationIdGetter) {
log.debug("getLocation:: parameters item: {}", item);
Expand Down Expand Up @@ -315,7 +321,7 @@ public CompletableFuture<Result<Collection<Location>>> fetchLocationsForServiceP
log.debug("fetchLocationsForServicePoint:: parameters servicePointId: {}", servicePointId);

return new CqlQueryFinder<>(locationsStorageClient, "locations", new LocationMapper()::toDomain)
.findByQuery(CqlQuery.match("servicePointIds", servicePointId))
.findByQuery(CqlQuery.match("servicePointIds", servicePointId), PageLimit.maximumLimit())
.thenApply(r -> r.map(MultipleRecords::getRecords));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ private void checkIn(RoutingContext routingContext) {
.thenComposeAsync(checkInLoan -> checkInLoan.combineAfter(
processAdapter::updateRequestQueue, CheckInContext::withRequestQueue))
.thenComposeAsync(r -> r.after(processAdapter::findFulfillableRequest))
.thenComposeAsync(checkInContextResult ->
checkInContextResult.combineAfter(processAdapter::findFloatingDestination,
CheckInContext::withItemAndUpdatedLoan))
.thenComposeAsync(updateRequestQueueResult -> updateRequestQueueResult.combineAfter(
processAdapter::updateItem, CheckInContext::withItemAndUpdatedLoan))
.thenApply(handleItemStatus -> handleItemStatus.next(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.apache.logging.log4j.Logger;
import org.folio.circulation.domain.CheckInContext;
import org.folio.circulation.domain.Item;
import org.folio.circulation.domain.Location;
import org.folio.circulation.domain.Loan;
import org.folio.circulation.domain.LoanCheckInService;
import org.folio.circulation.domain.OverdueFineService;
Expand All @@ -27,6 +28,7 @@
import org.folio.circulation.infrastructure.storage.feesandfines.FeeFineOwnerRepository;
import org.folio.circulation.infrastructure.storage.feesandfines.FeeFineRepository;
import org.folio.circulation.infrastructure.storage.inventory.ItemRepository;
import org.folio.circulation.infrastructure.storage.inventory.LocationRepository;
import org.folio.circulation.infrastructure.storage.loans.LoanPolicyRepository;
import org.folio.circulation.infrastructure.storage.loans.LoanRepository;
import org.folio.circulation.infrastructure.storage.loans.OverdueFinePolicyRepository;
Expand Down Expand Up @@ -57,6 +59,7 @@ class CheckInProcessAdapter {
private final UpdateRequestQueue requestQueueUpdate;
private final LoanRepository loanRepository;
private final ServicePointRepository servicePointRepository;
private final LocationRepository locationRepository;
private final UserRepository userRepository;
private final AddressTypeRepository addressTypeRepository;
private final LogCheckInService logCheckInService;
Expand All @@ -75,6 +78,7 @@ class CheckInProcessAdapter {
RequestQueueRepository requestQueueRepository,
UpdateItem updateItem, UpdateRequestQueue requestQueueUpdate,
LoanRepository loanRepository, ServicePointRepository servicePointRepository,
LocationRepository locationRepository,
UserRepository userRepository,
AddressTypeRepository addressTypeRepository,
LogCheckInService logCheckInService,
Expand All @@ -93,6 +97,7 @@ class CheckInProcessAdapter {
this.requestQueueUpdate = requestQueueUpdate;
this.loanRepository = loanRepository;
this.servicePointRepository = servicePointRepository;
this.locationRepository = locationRepository;
this.userRepository = userRepository;
this.addressTypeRepository = addressTypeRepository;
this.logCheckInService = logCheckInService;
Expand Down Expand Up @@ -134,6 +139,7 @@ public static CheckInProcessAdapter newInstance(Clients clients,
requestQueueRepository),
loanRepository,
new ServicePointRepository(clients),
LocationRepository.using(clients),
userRepository,
new AddressTypeRepository(clients),
new LogCheckInService(clients),
Expand Down Expand Up @@ -296,4 +302,19 @@ CompletableFuture<Result<CheckInContext>> findFulfillableRequest(CheckInContext
return requestQueueService.findRequestFulfillableByItem(context.getItem(), context.getRequestQueue())
.thenApply(r -> r.map(context::withHighestPriorityFulfillableRequest));
}

CompletableFuture<Result<Item>> findFloatingDestination(CheckInContext context) {
Item item = context.getItem();
if (item.getLocation().isFloatingCollection()) {
return locationRepository.fetchLocationsForServicePoint(context.getCheckInServicePointId().toString())
.thenApply(rLocations -> rLocations.map(locations -> locations.stream()
.filter(Location::isFloatingCollection).findFirst()
.map(item::withFloatDestinationLocation).orElse(item)))
.thenCompose(it -> locationRepository.getFloatDestinationLocation(it.value()))
.thenApply(location -> Result.succeeded(item.withFloatDestinationLocation(location.value())));
} else {
return Result.ofAsync(item);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import io.vertx.core.json.JsonObject;

public class ItemMapper {

public Item toDomain(JsonObject representation) {
return new Item(getProperty(representation, "id"), representation,
Location.unknown(getProperty(representation, "effectiveLocationId")),
LastCheckIn.fromItemJson(representation),
CallNumberComponents.fromItemJson(representation),
getProperty(representation, "effectiveShelvingOrder"),
Location.unknown(getProperty(representation, "permanentLocationId")),
Location.unknown(),
getInTransitServicePoint(representation), false,
Holdings.unknown(getProperty(representation, "holdingsRecordId")),
Instance.unknown(),
Expand Down
Loading