diff --git a/NEWS.md b/NEWS.md
index 8880f4a6..c25416fd 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,8 @@
+## 1.0.2 2024-12-12
+* Copy Secure Patron name when cloning users (MODTLR-116)
+* Support for intermediate requests (MODTLR-98)
+* Search Slips API (MODTLR-75)
+
## 1.0.1 2024-11-30
* Merge `ecs-tlr-feature` branch into `master` (MODTLR-69)
* Create pickup service point in lending tenant (MODTLR-17)
diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json
index cc79c41d..8072b311 100644
--- a/descriptors/ModuleDescriptor-template.json
+++ b/descriptors/ModuleDescriptor-template.json
@@ -29,7 +29,8 @@
"users.item.post",
"inventory-storage.service-points.item.get",
"inventory-storage.service-points.collection.get",
- "inventory-storage.service-points.item.post"
+ "inventory-storage.service-points.item.post",
+ "user-tenants.collection.get"
]
},
{
@@ -123,7 +124,6 @@
"permissionsRequired": ["tlr.pick-slips.collection.get"],
"modulePermissions": [
"user-tenants.collection.get",
- "search.instances.collection.get",
"circulation-storage.requests.item.get",
"circulation-storage.requests.collection.get",
"users.item.get",
@@ -135,7 +135,31 @@
"addresstypes.item.get",
"addresstypes.collection.get",
"inventory-storage.service-points.item.get",
- "inventory-storage.service-points.collection.get"
+ "inventory-storage.service-points.collection.get",
+ "inventory-storage.instances.item.get",
+ "inventory-storage.instances.collection.get"
+ ]
+ },
+ {
+ "methods": ["GET"],
+ "pathPattern": "/tlr/staff-slips/search-slips/{servicePointId}",
+ "permissionsRequired": ["tlr.search-slips.collection.get"],
+ "modulePermissions": [
+ "user-tenants.collection.get",
+ "circulation-storage.requests.item.get",
+ "circulation-storage.requests.collection.get",
+ "users.item.get",
+ "users.collection.get",
+ "usergroups.item.get",
+ "usergroups.collection.get",
+ "departments.item.get",
+ "departments.collection.get",
+ "addresstypes.item.get",
+ "addresstypes.collection.get",
+ "inventory-storage.service-points.item.get",
+ "inventory-storage.service-points.collection.get",
+ "inventory-storage.instances.item.get",
+ "inventory-storage.instances.collection.get"
]
}
]
@@ -244,6 +268,10 @@
"permissionName": "tlr.pick-slips.collection.get",
"displayName": "ecs-tlr - pick slips",
"description": "Get pick slips"
+ }, {
+ "permissionName": "tlr.search-slips.collection.get",
+ "displayName": "ecs-tlr - search slips",
+ "description": "Get search slips"
},
{
"permissionName": "tlr.ecs-request-external.post",
diff --git a/pom.xml b/pom.xml
index f8f92315..00af855e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
org.folio
mod-tlr
mod-tlr
- 1.0.2-SNAPSHOT
+ 1.0.3-SNAPSHOT
FOLIO mod-tlr module
jar
diff --git a/src/main/java/org/folio/client/feign/HoldingClient.java b/src/main/java/org/folio/client/feign/HoldingClient.java
new file mode 100644
index 00000000..4d69cbf4
--- /dev/null
+++ b/src/main/java/org/folio/client/feign/HoldingClient.java
@@ -0,0 +1,16 @@
+package org.folio.client.feign;
+
+import org.folio.domain.dto.HoldingsRecord;
+import org.folio.domain.dto.HoldingsRecords;
+import org.folio.spring.config.FeignClientConfiguration;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+@FeignClient(name = "holdings", url = "holdings-storage/holdings", configuration = FeignClientConfiguration.class)
+public interface HoldingClient extends GetByQueryClient {
+
+ @GetMapping("/{id}")
+ HoldingsRecord get(@PathVariable String id);
+
+}
diff --git a/src/main/java/org/folio/client/feign/InstanceClient.java b/src/main/java/org/folio/client/feign/InstanceClient.java
index f4a211d1..6d30b8e8 100644
--- a/src/main/java/org/folio/client/feign/InstanceClient.java
+++ b/src/main/java/org/folio/client/feign/InstanceClient.java
@@ -1,5 +1,6 @@
package org.folio.client.feign;
+import org.folio.domain.dto.Instances;
import org.folio.domain.dto.InventoryInstance;
import org.folio.spring.config.FeignClientConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
@@ -7,7 +8,7 @@
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "instances", url = "instance-storage/instances", configuration = FeignClientConfiguration.class)
-public interface InstanceClient {
+public interface InstanceClient extends GetByQueryClient {
@GetMapping("/{id}")
InventoryInstance get(@PathVariable String id);
diff --git a/src/main/java/org/folio/controller/StaffSlipsController.java b/src/main/java/org/folio/controller/StaffSlipsController.java
index 0a4f031f..f53cedf1 100644
--- a/src/main/java/org/folio/controller/StaffSlipsController.java
+++ b/src/main/java/org/folio/controller/StaffSlipsController.java
@@ -5,10 +5,13 @@
import java.util.UUID;
import org.folio.domain.dto.PickSlipsResponse;
+import org.folio.domain.dto.SearchSlipsResponse;
import org.folio.domain.dto.StaffSlip;
-import org.folio.rest.resource.PickSlipsApi;
+import org.folio.rest.resource.StaffSlipsApi;
import org.folio.service.impl.PickSlipsService;
+import org.folio.service.impl.SearchSlipsService;
import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.AllArgsConstructor;
@@ -17,9 +20,11 @@
@RestController
@Log4j2
@AllArgsConstructor
-public class StaffSlipsController implements PickSlipsApi {
+@RequestMapping("/tlr/staff-slips")
+public class StaffSlipsController implements StaffSlipsApi {
private final PickSlipsService pickSlipsService;
+ private final SearchSlipsService searchSlipsService;
@Override
public ResponseEntity getPickSlips(UUID servicePointId) {
@@ -30,4 +35,14 @@ public ResponseEntity getPickSlips(UUID servicePointId) {
.pickSlips(new ArrayList<>(pickSlips))
.totalRecords(pickSlips.size()));
}
+
+ @Override
+ public ResponseEntity getSearchSlips(UUID servicePointId) {
+ log.info("getSearchSlips:: servicePointId={}", servicePointId);
+ Collection searchSlips = searchSlipsService.getStaffSlips(servicePointId.toString());
+
+ return ResponseEntity.ok(new SearchSlipsResponse()
+ .searchSlips(new ArrayList<>(searchSlips))
+ .totalRecords(searchSlips.size()));
+ }
}
diff --git a/src/main/java/org/folio/domain/entity/EcsTlrEntity.java b/src/main/java/org/folio/domain/entity/EcsTlrEntity.java
index 3afd5616..28f41f39 100644
--- a/src/main/java/org/folio/domain/entity/EcsTlrEntity.java
+++ b/src/main/java/org/folio/domain/entity/EcsTlrEntity.java
@@ -40,4 +40,8 @@ public class EcsTlrEntity {
private UUID secondaryRequestId;
private String secondaryRequestTenantId;
private UUID secondaryRequestDcbTransactionId;
+ private UUID intermediateRequestId;
+ private String intermediateRequestTenantId;
+ private UUID intermediateRequestDcbTransactionId;
+
}
diff --git a/src/main/java/org/folio/service/DcbService.java b/src/main/java/org/folio/service/DcbService.java
index c687bfcd..7b8cb372 100644
--- a/src/main/java/org/folio/service/DcbService.java
+++ b/src/main/java/org/folio/service/DcbService.java
@@ -8,8 +8,11 @@
import org.folio.domain.entity.EcsTlrEntity;
public interface DcbService {
+ void createTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest);
void createLendingTransaction(EcsTlrEntity ecsTlr);
- void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request);
+ void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request);
+ void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request);
+ void createPickupTransaction(EcsTlrEntity ecsTlr, Request request);
TransactionStatusResponse getTransactionStatus(UUID transactionId, String tenantId);
TransactionStatusResponse updateTransactionStatus(UUID transactionId,
TransactionStatus.StatusEnum newStatus, String tenantId);
diff --git a/src/main/java/org/folio/service/InventoryService.java b/src/main/java/org/folio/service/InventoryService.java
index 4f3b4359..0cdce9d1 100644
--- a/src/main/java/org/folio/service/InventoryService.java
+++ b/src/main/java/org/folio/service/InventoryService.java
@@ -3,6 +3,8 @@
import java.util.Collection;
import org.folio.domain.dto.Campus;
+import org.folio.domain.dto.HoldingsRecord;
+import org.folio.domain.dto.Instance;
import org.folio.domain.dto.Institution;
import org.folio.domain.dto.Item;
import org.folio.domain.dto.Library;
@@ -12,7 +14,9 @@
public interface InventoryService {
Collection- findItems(CqlQuery query, String idIndex, Collection ids);
- Collection
- findItems(Collection ids);
+ Collection findHoldings(CqlQuery query, String idIndex, Collection ids);
+ Collection findHoldings(Collection ids);
+ Collection findInstances(Collection ids);
Collection findMaterialTypes(Collection ids);
Collection findLoanTypes(Collection ids);
Collection findLibraries(Collection ids);
diff --git a/src/main/java/org/folio/service/RequestService.java b/src/main/java/org/folio/service/RequestService.java
index 6ef95b05..e9e86fe1 100644
--- a/src/main/java/org/folio/service/RequestService.java
+++ b/src/main/java/org/folio/service/RequestService.java
@@ -9,28 +9,28 @@
import org.folio.domain.dto.InventoryItem;
import org.folio.domain.dto.ReorderQueue;
import org.folio.domain.dto.Request;
-import org.folio.domain.entity.EcsTlrEntity;
import org.folio.support.CqlQuery;
public interface RequestService {
- RequestWrapper createPrimaryRequest(Request request, String borrowingTenantId);
+ RequestWrapper createPrimaryRequest(Request request, String primaryRequestTenantId,
+ String secondaryRequestTenantId);
- RequestWrapper createSecondaryRequest(Request request, String borrowingTenantId,
- Collection lendingTenantIds);
+ RequestWrapper createSecondaryRequest(Request request, String primaryRequestTenantId,
+ Collection secondaryRequestTenantIds);
- CirculationItem createCirculationItem(EcsTlrEntity ecsTlr, Request secondaryRequest,
- String borrowingTenantId, String lendingTenantId);
+ RequestWrapper createIntermediateRequest(Request intermediateRequest,
+ String primaryRequestTenantId, String intermediateRequestTenantId,
+ String secondaryRequestTenantId);
CirculationItem updateCirculationItemOnRequestCreation(CirculationItem circulationItem,
Request secondaryRequest);
InventoryItem getItemFromStorage(String itemId, String tenantId);
-
InventoryInstance getInstanceFromStorage(String instanceId, String tenantId);
-
Request getRequestFromStorage(String requestId, String tenantId);
Request getRequestFromStorage(String requestId);
Collection getRequestsFromStorage(CqlQuery query, String idIndex, Collection ids);
+ Collection getRequestsFromStorage(CqlQuery query);
Request updateRequestInStorage(Request request, String tenantId);
List getRequestsQueueByInstanceId(String instanceId, String tenantId);
List getRequestsQueueByInstanceId(String instanceId);
diff --git a/src/main/java/org/folio/service/TenantService.java b/src/main/java/org/folio/service/TenantService.java
index c3d0da04..ec83538f 100644
--- a/src/main/java/org/folio/service/TenantService.java
+++ b/src/main/java/org/folio/service/TenantService.java
@@ -5,7 +5,7 @@
import org.folio.domain.entity.EcsTlrEntity;
public interface TenantService {
- String getBorrowingTenant(EcsTlrEntity ecsTlr);
+ String getPrimaryRequestTenantId(EcsTlrEntity ecsTlr);
- List getLendingTenants(EcsTlrEntity ecsTlr);
+ List getSecondaryRequestTenants(EcsTlrEntity ecsTlr);
}
diff --git a/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java b/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java
index 8ff2866f..f93cc6f9 100644
--- a/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java
+++ b/src/main/java/org/folio/service/impl/AllowedServicePointsServiceImpl.java
@@ -62,8 +62,6 @@ private AllowedServicePointsResponse getForCreate(AllowedServicePointsRequest re
Map recall = new HashMap<>();
for (String tenantId : getLendingTenants(request)) {
var servicePoints = getAllowedServicePointsFromTenant(request, patronGroupId, tenantId);
- log.info("getForCreate:: service points from {}: {}", tenantId, servicePoints);
-
combineAndFilterDuplicates(page, servicePoints.getPage());
combineAndFilterDuplicates(hold, servicePoints.getHold());
combineAndFilterDuplicates(recall, servicePoints.getRecall());
diff --git a/src/main/java/org/folio/service/impl/DcbServiceImpl.java b/src/main/java/org/folio/service/impl/DcbServiceImpl.java
index 01f425d4..99017e46 100644
--- a/src/main/java/org/folio/service/impl/DcbServiceImpl.java
+++ b/src/main/java/org/folio/service/impl/DcbServiceImpl.java
@@ -1,7 +1,9 @@
package org.folio.service.impl;
import static org.folio.domain.dto.DcbTransaction.RoleEnum.BORROWER;
+import static org.folio.domain.dto.DcbTransaction.RoleEnum.BORROWING_PICKUP;
import static org.folio.domain.dto.DcbTransaction.RoleEnum.LENDER;
+import static org.folio.domain.dto.DcbTransaction.RoleEnum.PICKUP;
import java.util.UUID;
@@ -9,6 +11,7 @@
import org.folio.client.feign.DcbTransactionClient;
import org.folio.domain.dto.DcbItem;
import org.folio.domain.dto.DcbTransaction;
+import org.folio.domain.dto.DcbTransaction.RoleEnum;
import org.folio.domain.dto.Request;
import org.folio.domain.dto.TransactionStatus;
import org.folio.domain.dto.TransactionStatusResponse;
@@ -43,27 +46,53 @@ public void createLendingTransaction(EcsTlrEntity ecsTlr) {
DcbTransaction transaction = new DcbTransaction()
.requestId(ecsTlr.getSecondaryRequestId().toString())
.role(LENDER);
- final UUID lendingTransactionId = createTransaction(transaction, ecsTlr.getSecondaryRequestTenantId());
- ecsTlr.setSecondaryRequestDcbTransactionId(lendingTransactionId);
+ final UUID transactionId = createTransaction(transaction, ecsTlr.getSecondaryRequestTenantId());
+ ecsTlr.setSecondaryRequestDcbTransactionId(transactionId);
log.info("createTransactions:: lending transaction {} for ECS TLR {} created",
- () -> lendingTransactionId, ecsTlr::getId);
+ () -> transactionId, ecsTlr::getId);
}
@Override
- public void createBorrowingTransaction(EcsTlrEntity ecsTlr, Request request) {
- log.info("createBorrowingTransaction:: creating borrowing transaction for ECS TLR {}", ecsTlr::getId);
+ public void createBorrowerTransaction(EcsTlrEntity ecsTlr, Request request) {
+ log.info("createBorrowerTransaction:: creating borrower transaction for ECS TLR {}", ecsTlr::getId);
+ DcbTransaction transaction = buildTransaction(request, BORROWER, ecsTlr.getIntermediateRequestId());
+ final UUID transactionId = createTransaction(transaction, ecsTlr.getIntermediateRequestTenantId());
+ ecsTlr.setIntermediateRequestDcbTransactionId(transactionId);
+ log.info("createBorrowerTransaction:: borrower transaction {} for ECS TLR {} created",
+ () -> transactionId, ecsTlr::getId);
+ }
+
+ @Override
+ public void createBorrowingPickupTransaction(EcsTlrEntity ecsTlr, Request request) {
+ log.info("createBorrowingPickupTransaction:: creating borrowing-pickup transaction for ECS TLR {}",
+ ecsTlr::getId);
+ DcbTransaction transaction = buildTransaction(request, BORROWING_PICKUP, ecsTlr.getPrimaryRequestId());
+ final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId());
+ ecsTlr.setPrimaryRequestDcbTransactionId(transactionId);
+ log.info("createBorrowingPickupTransaction:: borrowing-pickup transaction {} for ECS TLR {} created",
+ () -> transactionId, ecsTlr::getId);
+ }
+
+ @Override
+ public void createPickupTransaction(EcsTlrEntity ecsTlr, Request request) {
+ log.info("createPickupTransaction:: creating pickup transaction for ECS TLR {}", ecsTlr.getId());
+ DcbTransaction transaction = buildTransaction(request, PICKUP, ecsTlr.getPrimaryRequestId());
+ final UUID transactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId());
+ ecsTlr.setPrimaryRequestDcbTransactionId(transactionId);
+ log.info("createPickupTransaction:: pickup transaction {} for ECS TLR {} created",
+ () -> transactionId, ecsTlr::getId);
+ }
+
+ private DcbTransaction buildTransaction(Request request, RoleEnum role, UUID requestId) {
DcbItem dcbItem = new DcbItem()
.id(request.getItemId())
.title(request.getInstance().getTitle())
.barcode(request.getItem().getBarcode());
- DcbTransaction transaction = new DcbTransaction()
- .requestId(ecsTlr.getPrimaryRequestId().toString())
+
+ return new DcbTransaction()
+ .requestId(requestId.toString())
.item(dcbItem)
- .role(BORROWER);
- final UUID borrowingTransactionId = createTransaction(transaction, ecsTlr.getPrimaryRequestTenantId());
- ecsTlr.setPrimaryRequestDcbTransactionId(borrowingTransactionId);
- log.info("createBorrowingTransaction:: borrowing transaction {} for ECS TLR {} created",
- () -> borrowingTransactionId, ecsTlr::getId);
+ .role(role);
}
private UUID createTransaction(DcbTransaction transaction, String tenantId) {
@@ -97,4 +126,21 @@ public TransactionStatusResponse updateTransactionStatus(UUID transactionId,
transactionId.toString(), new TransactionStatus().status(newStatus)));
}
+ @Override
+ public void createTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest) {
+ log.info("createTransactions:: creating transactions for ECS TLR {}", ecsTlr::getId);
+ if (secondaryRequest.getItemId() == null) {
+ log.info("createDcbTransactions:: secondary request has no item ID");
+ return;
+ }
+ createLendingTransaction(ecsTlr);
+ log.info("createTransactions:: intermediate request ID: {}", ecsTlr::getIntermediateRequestId);
+ if (ecsTlr.getIntermediateRequestId() == null) {
+ createBorrowingPickupTransaction(ecsTlr, secondaryRequest);
+ } else {
+ createBorrowerTransaction(ecsTlr, secondaryRequest);
+ createPickupTransaction(ecsTlr, secondaryRequest);
+ }
+ }
+
}
diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java
index b3496747..a9b3b702 100644
--- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java
+++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java
@@ -1,14 +1,19 @@
package org.folio.service.impl;
+import static java.util.Optional.of;
+import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.INTERMEDIATE;
+import static org.folio.domain.dto.Request.EcsRequestPhaseEnum.PRIMARY;
+
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
+import java.util.stream.Collectors;
import org.folio.domain.RequestWrapper;
-import org.folio.domain.dto.CirculationItem;
import org.folio.domain.dto.EcsTlr;
import org.folio.domain.dto.Request;
+import org.folio.domain.dto.Request.EcsRequestPhaseEnum;
import org.folio.domain.entity.EcsTlrEntity;
import org.folio.domain.mapper.EcsTlrMapper;
import org.folio.exception.TenantPickingException;
@@ -17,6 +22,7 @@
import org.folio.service.EcsTlrService;
import org.folio.service.RequestService;
import org.folio.service.TenantService;
+import org.folio.service.UserTenantsService;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
@@ -32,6 +38,7 @@ public class EcsTlrServiceImpl implements EcsTlrService {
private final TenantService tenantService;
private final RequestService requestService;
private final DcbService dcbService;
+ private final UserTenantsService userTenantsService;
@Override
public Optional get(UUID id) {
@@ -47,23 +54,35 @@ public EcsTlr create(EcsTlr ecsTlrDto) {
ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId());
final EcsTlrEntity ecsTlr = requestsMapper.mapDtoToEntity(ecsTlrDto);
- String borrowingTenantId = getBorrowingTenant(ecsTlr);
- Collection lendingTenantIds = getLendingTenants(ecsTlr);
- RequestWrapper secondaryRequest = requestService.createSecondaryRequest(
- buildSecondaryRequest(ecsTlr), borrowingTenantId, lendingTenantIds);
-
- log.info("create:: Creating circulation item for ECS TLR (ILR) {}", ecsTlrDto.getId());
- CirculationItem circulationItem = requestService.createCirculationItem(ecsTlr,
- secondaryRequest.request(), borrowingTenantId, secondaryRequest.tenantId());
+ String primaryRequestTenantId = getPrimaryRequestTenant(ecsTlr);
+ Collection secondaryRequestsTenantIds = getSecondaryRequestTenants(ecsTlr).stream()
+ .filter(tenantId -> !tenantId.equals(primaryRequestTenantId))
+ .collect(Collectors.toList());
- RequestWrapper primaryRequest = requestService.createPrimaryRequest(
- buildPrimaryRequest(secondaryRequest.request()), borrowingTenantId);
+ log.info("create:: Creating secondary request for ECS TLR (ILR), instance {}, item {}, requester {}",
+ ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId());
+ RequestWrapper secondaryRequestWrapper = requestService.createSecondaryRequest(
+ buildSecondaryRequest(ecsTlr), primaryRequestTenantId, secondaryRequestsTenantIds);
+ Request secondaryRequest = secondaryRequestWrapper.request();
+ String secondaryRequestTenantId = secondaryRequestWrapper.tenantId();
- requestService.updateCirculationItemOnRequestCreation(circulationItem,
- secondaryRequest.request());
+ log.info("create:: Creating primary request for ECS TLR (ILR), instance {}, item {}, requester {}",
+ ecsTlrDto.getInstanceId(), ecsTlrDto.getItemId(), ecsTlrDto.getRequesterId());
+ RequestWrapper primaryRequestWrapper = requestService.createPrimaryRequest(
+ buildPrimaryRequest(secondaryRequest), primaryRequestTenantId, secondaryRequestTenantId);
+
+ updateEcsTlr(ecsTlr, primaryRequestWrapper, secondaryRequestWrapper);
+
+ var centralTenantId = userTenantsService.getCentralTenantId();
+ if (!primaryRequestTenantId.equals(centralTenantId)) {
+ log.info("create:: Primary request tenant is not central, creating intermediate request");
+ RequestWrapper intermediateRequest = requestService.createIntermediateRequest(
+ buildIntermediateRequest(secondaryRequest), primaryRequestTenantId, centralTenantId,
+ secondaryRequestTenantId);
+ updateEcsTlrWithIntermediateRequest(ecsTlr, intermediateRequest);
+ }
- updateEcsTlr(ecsTlr, primaryRequest, secondaryRequest);
- createDcbTransactions(ecsTlr, secondaryRequest.request());
+ dcbService.createTransactions(ecsTlr, secondaryRequest);
return requestsMapper.mapEntityToDto(save(ecsTlr));
}
@@ -90,28 +109,28 @@ public boolean delete(UUID requestId) {
return false;
}
- private String getBorrowingTenant(EcsTlrEntity ecsTlr) {
- log.info("getBorrowingTenant:: getting borrowing tenant");
- final String borrowingTenantId = tenantService.getBorrowingTenant(ecsTlr);
- log.info("getBorrowingTenant:: borrowing tenant: {}", borrowingTenantId);
+ private String getPrimaryRequestTenant(EcsTlrEntity ecsTlr) {
+ log.info("getPrimaryRequestTenant:: getting primary request tenant");
+ final String primaryRequestTenantId = tenantService.getPrimaryRequestTenantId(ecsTlr);
+ log.info("getPrimaryRequestTenant:: primary request tenant: {}", primaryRequestTenantId);
- if (borrowingTenantId == null) {
- throw new TenantPickingException("Failed to get borrowing tenant");
+ if (primaryRequestTenantId == null) {
+ throw new TenantPickingException("Failed to get primary request tenant");
}
- return borrowingTenantId;
+ return primaryRequestTenantId;
}
- private Collection getLendingTenants(EcsTlrEntity ecsTlr) {
+ private Collection getSecondaryRequestTenants(EcsTlrEntity ecsTlr) {
final String instanceId = ecsTlr.getInstanceId().toString();
- log.info("getLendingTenants:: looking for lending tenants for instance {}", instanceId);
- List tenantIds = tenantService.getLendingTenants(ecsTlr);
+ log.info("getSecondaryRequestTenants:: looking for secondary request tenants for instance {}", instanceId);
+ List tenantIds = tenantService.getSecondaryRequestTenants(ecsTlr);
if (tenantIds.isEmpty()) {
- log.error("getLendingTenants:: failed to find lending tenants for instance: {}", instanceId);
- throw new TenantPickingException("Failed to find lending tenants for instance " + instanceId);
+ log.error("getSecondaryRequestTenants:: failed to find lending tenants for instance: {}", instanceId);
+ throw new TenantPickingException("Failed to find secondary request tenants for instance " + instanceId);
}
- log.info("getLendingTenants:: lending tenants found: {}", tenantIds);
+ log.info("getSecondaryRequestTenants:: secondary request tenants found: {}", tenantIds);
return tenantIds;
}
@@ -125,6 +144,14 @@ private EcsTlrEntity save(EcsTlrEntity ecsTlr) {
}
private static Request buildPrimaryRequest(Request secondaryRequest) {
+ return buildRequest(secondaryRequest, PRIMARY);
+ }
+
+ private static Request buildIntermediateRequest(Request secondaryRequest) {
+ return buildRequest(secondaryRequest, INTERMEDIATE);
+ }
+
+ private static Request buildRequest(Request secondaryRequest, EcsRequestPhaseEnum ecsRequestPhase) {
return new Request()
.id(secondaryRequest.getId())
.instanceId(secondaryRequest.getInstanceId())
@@ -134,14 +161,14 @@ private static Request buildPrimaryRequest(Request secondaryRequest) {
.requestDate(secondaryRequest.getRequestDate())
.requestLevel(secondaryRequest.getRequestLevel())
.requestType(secondaryRequest.getRequestType())
- .ecsRequestPhase(Request.EcsRequestPhaseEnum.PRIMARY)
+ .ecsRequestPhase(ecsRequestPhase)
.fulfillmentPreference(secondaryRequest.getFulfillmentPreference())
.pickupServicePointId(secondaryRequest.getPickupServicePointId());
}
private Request buildSecondaryRequest(EcsTlrEntity ecsTlr) {
return requestsMapper.mapEntityToRequest(ecsTlr)
- .ecsRequestPhase(Request.EcsRequestPhaseEnum.SECONDARY);
+ .ecsRequestPhase(EcsRequestPhaseEnum.SECONDARY);
}
private static void updateEcsTlr(EcsTlrEntity ecsTlr, RequestWrapper primaryRequest,
@@ -153,7 +180,7 @@ private static void updateEcsTlr(EcsTlrEntity ecsTlr, RequestWrapper primaryRequ
ecsTlr.setPrimaryRequestId(UUID.fromString(primaryRequest.request().getId()));
ecsTlr.setSecondaryRequestId(UUID.fromString(secondaryRequest.request().getId()));
- Optional.of(secondaryRequest.request())
+ of(secondaryRequest.request())
.map(Request::getItemId)
.map(UUID::fromString)
.ifPresent(ecsTlr::setItemId);
@@ -162,13 +189,15 @@ private static void updateEcsTlr(EcsTlrEntity ecsTlr, RequestWrapper primaryRequ
log.debug("updateEcsTlr:: ECS TLR: {}", () -> ecsTlr);
}
- private void createDcbTransactions(EcsTlrEntity ecsTlr, Request secondaryRequest) {
- if (secondaryRequest.getItemId() == null) {
- log.info("createDcbTransactions:: secondary request has no item ID");
- return;
- }
- dcbService.createBorrowingTransaction(ecsTlr, secondaryRequest);
- dcbService.createLendingTransaction(ecsTlr);
+ private static void updateEcsTlrWithIntermediateRequest(EcsTlrEntity ecsTlr,
+ RequestWrapper intermediateRequest) {
+
+ log.info("updateEcsTlrWithIntermediateRequest:: updating ECS TLR in memory");
+ ecsTlr.setIntermediateRequestTenantId(intermediateRequest.tenantId());
+ ecsTlr.setIntermediateRequestId(UUID.fromString(intermediateRequest.request().getId()));
+
+ log.info("updateEcsTlrWithIntermediateRequest:: ECS TLR updated in memory");
+ log.debug("updateEcsTlrWithIntermediateRequest:: ECS TLR: {}", () -> ecsTlr);
}
}
diff --git a/src/main/java/org/folio/service/impl/InventoryServiceImpl.java b/src/main/java/org/folio/service/impl/InventoryServiceImpl.java
index b2018d63..d32319f1 100644
--- a/src/main/java/org/folio/service/impl/InventoryServiceImpl.java
+++ b/src/main/java/org/folio/service/impl/InventoryServiceImpl.java
@@ -2,6 +2,8 @@
import java.util.Collection;
+import org.folio.client.feign.HoldingClient;
+import org.folio.client.feign.InstanceClient;
import org.folio.client.feign.ItemClient;
import org.folio.client.feign.LoanTypeClient;
import org.folio.client.feign.LocationCampusClient;
@@ -10,6 +12,10 @@
import org.folio.client.feign.MaterialTypeClient;
import org.folio.domain.dto.Campus;
import org.folio.domain.dto.Campuses;
+import org.folio.domain.dto.HoldingsRecord;
+import org.folio.domain.dto.HoldingsRecords;
+import org.folio.domain.dto.Instance;
+import org.folio.domain.dto.Instances;
import org.folio.domain.dto.Institution;
import org.folio.domain.dto.Institutions;
import org.folio.domain.dto.Item;
@@ -34,6 +40,8 @@
public class InventoryServiceImpl implements InventoryService {
private final ItemClient itemClient;
+ private final InstanceClient instanceClient;
+ private final HoldingClient holdingClient;
private final MaterialTypeClient materialTypeClient;
private final LoanTypeClient loanTypeClient;
private final LocationLibraryClient libraryClient;
@@ -45,65 +53,64 @@ public Collection
- findItems(CqlQuery query, String idIndex, Collection items = BulkFetcher.fetch(itemClient, query, idIndex, ids, Items::getItems);
- log.info("findItems:: found {} items", items::size);
- return items;
+ return BulkFetcher.fetch(itemClient, query, idIndex, ids, Items::getItems);
}
@Override
- public Collection
- findItems(Collection ids) {
- log.info("findItems:: searching items by {} IDs", ids::size);
- log.debug("findItems:: ids={}", ids);
- Collection
- items = BulkFetcher.fetch(itemClient, ids, Items::getItems);
- log.info("findItems:: found {} items", items::size);
- return items;
+ public Collection findHoldings(CqlQuery query, String idIndex, Collection ids) {
+ log.info("findHoldings:: searching holdings by query and index: query={}, index={}, ids={}",
+ query, idIndex, ids.size());
+ log.debug("findHoldings:: ids={}", ids);
+ return BulkFetcher.fetch(holdingClient, query, idIndex, ids, HoldingsRecords::getHoldingsRecords);
+ }
+
+ @Override
+ public Collection findHoldings(Collection ids) {
+ log.info("findHoldings:: searching holdings by {} IDs", ids::size);
+ return BulkFetcher.fetch(holdingClient, ids, HoldingsRecords::getHoldingsRecords);
+ }
+
+
+ @Override
+ public Collection findInstances(Collection ids) {
+ log.info("findInstances:: searching instances by {} IDs", ids::size);
+ log.debug("findInstances:: ids={}", ids);
+ return BulkFetcher.fetch(instanceClient, ids, Instances::getInstances);
}
@Override
public Collection findMaterialTypes(Collection ids) {
log.info("findMaterialTypes:: searching material types by {} IDs", ids::size);
log.debug("findMaterialTypes:: ids={}", ids);
- Collection materialTypes = BulkFetcher.fetch(materialTypeClient, ids,
- MaterialTypes::getMtypes);
- log.info("findMaterialTypes:: found {} material types", materialTypes::size);
- return materialTypes;
+ return BulkFetcher.fetch(materialTypeClient, ids, MaterialTypes::getMtypes);
}
@Override
public Collection findLoanTypes(Collection ids) {
log.info("findLoanTypes:: searching loan types by {} IDs", ids::size);
log.debug("findLoanTypes:: ids={}", ids);
- Collection loanTypes = BulkFetcher.fetch(loanTypeClient, ids, LoanTypes::getLoantypes);
- log.info("findLoanTypes:: found {} loan types", loanTypes::size);
- return loanTypes;
+ return BulkFetcher.fetch(loanTypeClient, ids, LoanTypes::getLoantypes);
}
@Override
public Collection findLibraries(Collection ids) {
log.info("findLibraries:: searching libraries by {} IDs", ids::size);
log.debug("findLibraries:: ids={}", ids);
- Collection libraries = BulkFetcher.fetch(libraryClient, ids, Libraries::getLoclibs);
- log.info("findLibraries:: found {} libraries", libraries::size);
- return libraries;
+ return BulkFetcher.fetch(libraryClient, ids, Libraries::getLoclibs);
}
@Override
public Collection findCampuses(Collection ids) {
log.info("findCampuses:: searching campuses by {} IDs", ids::size);
log.debug("findCampuses:: ids={}", ids);
- Collection campuses = BulkFetcher.fetch(campusClient, ids, Campuses::getLoccamps);
- log.info("findCampuses:: found {} campuses", campuses::size);
- return campuses;
+ return BulkFetcher.fetch(campusClient, ids, Campuses::getLoccamps);
}
@Override
public Collection findInstitutions(Collection ids) {
log.info("findInstitutions:: searching institutions by {} IDs", ids::size);
log.debug("findInstitutions:: ids={}", ids);
- Collection institutions = BulkFetcher.fetch(institutionClient, ids,
- Institutions::getLocinsts);
- log.info("findInstitutions:: found {} institutions", institutions::size);
- return institutions;
+ return BulkFetcher.fetch(institutionClient, ids, Institutions::getLocinsts);
}
}
diff --git a/src/main/java/org/folio/service/impl/PickSlipsService.java b/src/main/java/org/folio/service/impl/PickSlipsService.java
index 17e41bc9..7dc19a07 100644
--- a/src/main/java/org/folio/service/impl/PickSlipsService.java
+++ b/src/main/java/org/folio/service/impl/PickSlipsService.java
@@ -12,7 +12,6 @@
import org.folio.service.InventoryService;
import org.folio.service.LocationService;
import org.folio.service.RequestService;
-import org.folio.service.SearchService;
import org.folio.service.ServicePointService;
import org.folio.service.UserGroupService;
import org.folio.service.UserService;
@@ -31,11 +30,10 @@ public PickSlipsService(LocationService locationService, InventoryService invent
RequestService requestService, ConsortiaService consortiaService,
SystemUserScopedExecutionService executionService, UserService userService,
UserGroupService userGroupService, DepartmentService departmentService,
- AddressTypeService addressTypeService, SearchService searchService,
- ServicePointService servicePointService) {
+ AddressTypeService addressTypeService, ServicePointService servicePointService) {
super(EnumSet.of(PAGED), EnumSet.of(OPEN_NOT_YET_FILLED), EnumSet.of(PAGE), locationService,
inventoryService, requestService, consortiaService, executionService, userService,
- userGroupService, departmentService, addressTypeService, searchService, servicePointService);
+ userGroupService, departmentService, addressTypeService, servicePointService);
}
}
diff --git a/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java b/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java
index a6f2f2d3..2ce021b5 100644
--- a/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java
+++ b/src/main/java/org/folio/service/impl/RequestBatchUpdateEventHandler.java
@@ -61,14 +61,14 @@ private void updateQueuePositionsForItemLevel(String itemId) {
}
private void updateQueuePositions(List unifiedQueue, boolean isTlrRequestQueue) {
- log.info("updateQueuePositions:: parameters unifiedQueue: {}", unifiedQueue);
+ log.debug("updateQueuePositions:: parameters unifiedQueue: {}", unifiedQueue);
List sortedPrimaryRequestIds = unifiedQueue.stream()
.filter(request -> PRIMARY == request.getEcsRequestPhase())
.filter(request -> request.getPosition() != null)
.sorted(Comparator.comparing(Request::getPosition))
.map(request -> UUID.fromString(request.getId()))
.toList();
- log.info("updateQueuePositions:: sortedPrimaryRequestIds: {}", sortedPrimaryRequestIds);
+ log.debug("updateQueuePositions:: sortedPrimaryRequestIds: {}", sortedPrimaryRequestIds);
List ecsTlrByPrimaryRequests = ecsTlrRepository.findByPrimaryRequestIdIn(
sortedPrimaryRequestIds);
@@ -101,7 +101,7 @@ private Map> groupSecondaryRequestsByTenantId(
private List sortEcsTlrEntities(List sortedPrimaryRequestIds,
List ecsTlrQueue) {
- log.info("sortEcsTlrEntities:: parameters sortedPrimaryRequestIds: {}, ecsTlrQueue: {}",
+ log.debug("sortEcsTlrEntities:: parameters sortedPrimaryRequestIds: {}, ecsTlrQueue: {}",
sortedPrimaryRequestIds, ecsTlrQueue);
Map ecsTlrByPrimaryRequestId = ecsTlrQueue.stream()
.collect(toMap(EcsTlrEntity::getPrimaryRequestId, Function.identity()));
@@ -109,7 +109,7 @@ private List sortEcsTlrEntities(List sortedPrimaryRequestIds
.stream()
.map(ecsTlrByPrimaryRequestId::get)
.toList();
- log.info("sortEcsTlrEntities:: result: {}", sortedEcsTlrQueue);
+ log.debug("sortEcsTlrEntities:: result: {}", sortedEcsTlrQueue);
return sortedEcsTlrQueue;
}
@@ -118,7 +118,7 @@ private void reorderSecondaryRequestsQueue(
Map> groupedSecondaryRequestsByTenantId,
List sortedEcsTlrQueue, boolean isTlrRequestQueue) {
- log.info("reorderSecondaryRequestsQueue:: parameters groupedSecondaryRequestsByTenantId: {}, " +
+ log.debug("reorderSecondaryRequestsQueue:: parameters groupedSecondaryRequestsByTenantId: {}, " +
"sortedEcsTlrQueue: {}", groupedSecondaryRequestsByTenantId, sortedEcsTlrQueue);
Map correctOrder = IntStream.range(0, sortedEcsTlrQueue.size())
@@ -198,12 +198,12 @@ private void updateReorderedRequests(List requestsWithUpdatedPositions,
new ReorderQueueReorderedQueueInner()
.id(request.getId())
.newPosition(request.getPosition())));
- log.info("updateReorderedRequests:: reorderQueue: {}", reorderQueue);
+ log.debug("updateReorderedRequests:: reorderQueue: {}", reorderQueue);
List requests = isTlrRequestQueue
? requestService.reorderRequestsQueueForInstance(id, tenantId, reorderQueue)
: requestService.reorderRequestsQueueForItem(id, tenantId, reorderQueue);
- log.info("updateReorderedRequests:: result: {}", requests);
+ log.debug("updateReorderedRequests:: result: {}", requests);
}
}
diff --git a/src/main/java/org/folio/service/impl/RequestEventHandler.java b/src/main/java/org/folio/service/impl/RequestEventHandler.java
index 770c28a7..f8087ace 100644
--- a/src/main/java/org/folio/service/impl/RequestEventHandler.java
+++ b/src/main/java/org/folio/service/impl/RequestEventHandler.java
@@ -118,29 +118,12 @@ private static boolean requestMatchesEcsTlr(EcsTlrEntity ecsTlr, Request updated
private void handlePrimaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) {
propagateChangesFromPrimaryToSecondaryRequest(ecsTlr, event);
- determineNewTransactionStatus(event).ifPresent(newTransactionStatus -> {
- if (newTransactionStatus == CANCELLED) {
- log.info("handlePrimaryRequestUpdate:: cancelling secondary DCB transaction");
- updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newTransactionStatus,
- ecsTlr.getSecondaryRequestTenantId());
- } else {
- updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newTransactionStatus,
- ecsTlr.getPrimaryRequestTenantId());
- }
- });
+ updateTransactionStatuses(event, ecsTlr);
}
private void handleSecondaryRequestUpdate(EcsTlrEntity ecsTlr, KafkaEvent event) {
processItemIdUpdate(ecsTlr, event.getData().getNewVersion());
- determineNewTransactionStatus(event).ifPresent(newTransactionStatus -> {
- updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newTransactionStatus,
- ecsTlr.getSecondaryRequestTenantId());
- if (newTransactionStatus == OPEN) {
- log.info("handleSecondaryRequestUpdate:: open primary DCB transaction");
- updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newTransactionStatus,
- ecsTlr.getPrimaryRequestTenantId());
- }
- });
+ updateTransactionStatuses(event, ecsTlr);
}
private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) {
@@ -151,8 +134,8 @@ private void processItemIdUpdate(EcsTlrEntity ecsTlr, Request updatedRequest) {
log.info("processItemIdUpdate:: updating ECS TLR {} with itemId {}", ecsTlr::getId,
updatedRequest::getItemId);
ecsTlr.setItemId(UUID.fromString(updatedRequest.getItemId()));
- dcbService.createLendingTransaction(ecsTlr);
- dcbService.createBorrowingTransaction(ecsTlr, updatedRequest);
+ // TODO: change this if Page request works
+ dcbService.createTransactions(ecsTlr, updatedRequest);
ecsTlrRepository.save(ecsTlr);
log.info("processItemIdUpdate: ECS TLR {} is updated", ecsTlr::getId);
}
@@ -186,19 +169,52 @@ private static Optional determineNewTransactionSta
return newTransactionStatus;
}
+ private void updateTransactionStatuses(KafkaEvent event, EcsTlrEntity ecsTlr) {
+ determineNewTransactionStatus(event)
+ .ifPresent(newStatus -> updateTransactionStatuses(newStatus, ecsTlr));
+ }
+
+ private void updateTransactionStatuses(TransactionStatus.StatusEnum newStatus, EcsTlrEntity ecsTlr) {
+ log.info("updateTransactionStatuses:: updating primary transaction status to {}", newStatus::getValue);
+ updateTransactionStatus(ecsTlr.getPrimaryRequestDcbTransactionId(), newStatus,
+ ecsTlr.getPrimaryRequestTenantId());
+
+ log.info("updateTransactionStatuses:: updating intermediate transaction status to {}", newStatus::getValue);
+ updateTransactionStatus(ecsTlr.getIntermediateRequestDcbTransactionId(), newStatus,
+ ecsTlr.getIntermediateRequestTenantId());
+
+ log.info("updateTransactionStatuses:: updating secondary transaction status to {}", newStatus::getValue);
+ updateTransactionStatus(ecsTlr.getSecondaryRequestDcbTransactionId(), newStatus,
+ ecsTlr.getSecondaryRequestTenantId());
+ }
+
private void updateTransactionStatus(UUID transactionId,
- TransactionStatus.StatusEnum newTransactionStatus, String tenant) {
+ TransactionStatus.StatusEnum newStatus, String tenantId) {
+
+ if (transactionId == null) {
+ log.info("updateTransactionStatus:: transaction ID is null, doing nothing");
+ return;
+ }
+ if (tenantId == null) {
+ log.info("updateTransactionStatus:: tenant ID is null, doing nothing");
+ return;
+ }
try {
- var currentStatus = dcbService.getTransactionStatus(transactionId, tenant).getStatus();
+ var currentStatus = dcbService.getTransactionStatus(transactionId, tenantId).getStatus();
log.info("updateTransactionStatus:: current transaction status: {}", currentStatus);
- if (newTransactionStatus.getValue().equals(currentStatus.getValue())) {
+ if (newStatus.getValue().equals(currentStatus.getValue())) {
log.info("updateTransactionStatus:: transaction status did not change, doing nothing");
return;
}
- dcbService.updateTransactionStatus(transactionId, newTransactionStatus, tenant);
+ log.info("updateTransactionStatus: changing status of transaction {} in tenant {} from {} to {}",
+ transactionId, tenantId, currentStatus.getValue(), newStatus.getValue());
+ dcbService.updateTransactionStatus(transactionId, newStatus, tenantId);
} catch (FeignException.NotFound e) {
log.error("updateTransactionStatus:: transaction {} not found: {}", transactionId, e.getMessage());
+ } catch (Exception e) {
+ log.error("updateTransactionStatus:: failed to update transaction status: {}", e::getMessage);
+ log.debug("updateTransactionStatus:: ", e);
}
}
diff --git a/src/main/java/org/folio/service/impl/RequestServiceImpl.java b/src/main/java/org/folio/service/impl/RequestServiceImpl.java
index 47f527c7..313d4b8e 100644
--- a/src/main/java/org/folio/service/impl/RequestServiceImpl.java
+++ b/src/main/java/org/folio/service/impl/RequestServiceImpl.java
@@ -4,6 +4,7 @@
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import java.util.UUID;
import org.folio.client.feign.CirculationClient;
@@ -23,7 +24,6 @@
import org.folio.domain.dto.Requests;
import org.folio.domain.dto.ServicePoint;
import org.folio.domain.dto.User;
-import org.folio.domain.entity.EcsTlrEntity;
import org.folio.exception.RequestCreatingException;
import org.folio.service.CloningService;
import org.folio.service.RequestService;
@@ -58,95 +58,159 @@ public class RequestServiceImpl implements RequestService {
public static final String HOLDINGS_RECORD_ID = "10cd3a5a-d36f-4c7a-bc4f-e1ae3cf820c9";
@Override
- public RequestWrapper createPrimaryRequest(Request request, String borrowingTenantId) {
- final String requestId = request.getId();
- log.info("createPrimaryRequest:: creating primary request {} in borrowing tenant ({})",
- requestId, borrowingTenantId);
- Request primaryRequest = executionService.executeSystemUserScoped(borrowingTenantId,
- () -> circulationClient.createRequest(request));
- log.info("createPrimaryRequest:: primary request {} created in borrowing tenant ({})",
- requestId, borrowingTenantId);
- log.debug("createPrimaryRequest:: primary request: {}", () -> primaryRequest);
-
- return new RequestWrapper(primaryRequest, borrowingTenantId);
+ public RequestWrapper createPrimaryRequest(Request primaryRequest,
+ String primaryRequestTenantId, String secondaryRequestTenantId) {
+
+ final String requestId = primaryRequest.getId();
+ log.info("createPrimaryRequest:: creating primary request {} in tenant {}", requestId,
+ primaryRequestTenantId);
+
+ return executionService.executeSystemUserScoped(primaryRequestTenantId, () -> {
+ CirculationItem circItem = createCirculationItem(primaryRequest, secondaryRequestTenantId);
+ Request request = circulationClient.createRequest(primaryRequest);
+ log.info("createPrimaryRequest:: primary request {} created in tenant {}",
+ requestId, primaryRequestTenantId);
+ log.debug("createPrimaryRequest:: primary request: {}", () -> request);
+ updateCirculationItemOnRequestCreation(circItem, request);
+ return new RequestWrapper(request, primaryRequestTenantId);
+ });
}
@Override
- public RequestWrapper createSecondaryRequest(Request request, String borrowingTenantId,
- Collection lendingTenantIds) {
+ public RequestWrapper createSecondaryRequest(Request request, String primaryRequestTenantId,
+ Collection secondaryRequestTenantIds) {
final String requestId = request.getId();
final String requesterId = request.getRequesterId();
final String pickupServicePointId = request.getPickupServicePointId();
log.info("createSecondaryRequest:: creating secondary request {} in one of potential " +
- "lending tenants: {}", requestId, lendingTenantIds);
+ "tenants: {}", requestId, secondaryRequestTenantIds);
- User primaryRequestRequester = executionService.executeSystemUserScoped(borrowingTenantId,
+ User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId,
() -> userService.find(requesterId));
ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped(
- borrowingTenantId, () -> servicePointService.find(pickupServicePointId));
+ primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId));
- for (String lendingTenantId : lendingTenantIds) {
+ for (String secondaryRequestTenantId : secondaryRequestTenantIds) {
try {
- return executionService.executeSystemUserScoped(lendingTenantId, () -> {
- log.info("createSecondaryRequest:: creating requester {} in lending tenant ({})",
- requesterId, lendingTenantId);
+ return executionService.executeSystemUserScoped(secondaryRequestTenantId, () -> {
+ log.info("createSecondaryRequest:: creating requester {} in tenant {}",
+ requesterId, secondaryRequestTenantId);
cloneRequester(primaryRequestRequester);
- log.info("createSecondaryRequest:: creating pickup service point {} in lending tenant ({})",
- pickupServicePointId, lendingTenantId);
+ log.info("createSecondaryRequest:: creating pickup service point {} in tenant {}",
+ pickupServicePointId, secondaryRequestTenantId);
servicePointCloningService.clone(primaryRequestPickupServicePoint);
- log.info("createSecondaryRequest:: creating secondary request {} in lending tenant ({})",
- requestId, lendingTenantId);
+ log.info("createSecondaryRequest:: creating secondary request {} in tenant {}",
+ requestId, secondaryRequestTenantId);
Request secondaryRequest = circulationClient.createRequest(request);
- log.info("createSecondaryRequest:: secondary request {} created in lending tenant ({})",
- requestId, lendingTenantId);
+ log.info("createSecondaryRequest:: secondary request {} created in tenant {}",
+ secondaryRequest.getId(), secondaryRequestTenantId);
log.debug("createSecondaryRequest:: secondary request: {}", () -> secondaryRequest);
- return new RequestWrapper(secondaryRequest, lendingTenantId);
+ return new RequestWrapper(secondaryRequest, secondaryRequestTenantId);
});
} catch (Exception e) {
- log.error("createSecondaryRequest:: failed to create secondary request in lending tenant ({}): {}",
- lendingTenantId, e.getMessage());
+ log.error("createSecondaryRequest:: failed to create secondary request in tenant {}: {}",
+ secondaryRequestTenantId, e.getMessage());
log.debug("createSecondaryRequest:: ", e);
}
}
String errorMessage = format(
- "Failed to create secondary request for instance %s in all potential lending tenants: %s",
- request.getInstanceId(), lendingTenantIds);
+ "Failed to create secondary request for instance %s in all potential tenants: %s",
+ request.getInstanceId(), secondaryRequestTenantIds);
log.error("createSecondaryRequest:: {}", errorMessage);
throw new RequestCreatingException(errorMessage);
}
@Override
- public CirculationItem createCirculationItem(EcsTlrEntity ecsTlr, Request secondaryRequest,
- String borrowingTenantId, String lendingTenantId) {
+ public RequestWrapper createIntermediateRequest(Request intermediateRequest,
+ String primaryRequestTenantId, String intermediateRequestTenantId,
+ String secondaryRequestTenantId) {
+
+ log.info("createIntermediateRequest:: creating intermediate request in tenant {}, instance {}," +
+ " item {}, requester {}", intermediateRequestTenantId, intermediateRequest.getInstanceId(),
+ intermediateRequest.getItemId(), intermediateRequest.getRequesterId());
+
+ try {
+ final String requesterId = intermediateRequest.getRequesterId();
+ final String pickupServicePointId = intermediateRequest.getPickupServicePointId();
+
+ User primaryRequestRequester = executionService.executeSystemUserScoped(primaryRequestTenantId,
+ () -> userService.find(requesterId));
+ ServicePoint primaryRequestPickupServicePoint = executionService.executeSystemUserScoped(
+ primaryRequestTenantId, () -> servicePointService.find(pickupServicePointId));
+
+ log.info("createIntermediateRequest:: creating requester {} in tenant {}",
+ requesterId, intermediateRequestTenantId);
+ cloneRequester(primaryRequestRequester);
+
+ log.info("createIntermediateRequest:: creating pickup service point {} in tenant {}",
+ pickupServicePointId, intermediateRequestTenantId);
+ servicePointCloningService.clone(primaryRequestPickupServicePoint);
+
+ CirculationItem circItem = createCirculationItem(intermediateRequest, secondaryRequestTenantId);
+
+ log.info("createIntermediateRequest:: creating intermediate request in tenant {}",
+ intermediateRequestTenantId);
+ Request request = circulationClient.createRequest(intermediateRequest);
+ log.info("createIntermediateRequest:: intermediate request {} created in tenant {}",
+ request.getId(), intermediateRequestTenantId);
+
+ updateCirculationItemOnRequestCreation(circItem, request);
+
+ return new RequestWrapper(request, intermediateRequestTenantId);
+ } catch (Exception e) {
+ log.error("createIntermediateRequest:: failed to create intermediate request in tenant {}: {}",
+ intermediateRequestTenantId, e.getMessage());
+ log.debug("createIntermediateRequest:: ", e);
+ }
+
+ String errorMessage = format(
+ "Failed to create intermediate request for instance %s, item %s, requester %s in tenant %s",
+ intermediateRequest.getInstanceId(), intermediateRequest.getItemId(), intermediateRequest.getRequesterId(), intermediateRequestTenantId);
+ log.error("createIntermediateRequest:: {}", errorMessage);
+ throw new RequestCreatingException(errorMessage);
+ }
- if (ecsTlr == null || secondaryRequest == null) {
- log.info("createCirculationItem:: ECS TLR or secondary request is null, skipping");
+ public CirculationItem createCirculationItem(Request request, String inventoryTenantId) {
+ if (request == null) {
+ log.warn("createCirculationItem:: request is null, skipping");
+ return null;
+ }
+ if (inventoryTenantId == null) {
+ log.warn("createCirculationItem:: inventory tenant ID is null, skipping");
return null;
}
- var itemId = secondaryRequest.getItemId();
- var instanceId = secondaryRequest.getInstanceId();
+ String itemId = request.getItemId();
+ String instanceId = request.getInstanceId();
+ String pickupLocation = request.getPickupServicePointId();
+
+ log.info("createCirculationItem:: creating circulation item, params: itemId={}, instanceId={}, " +
+ "pickupLocation={}, inventoryTenantId={}", itemId, instanceId, pickupLocation, inventoryTenantId);
if (itemId == null || instanceId == null) {
log.info("createCirculationItem:: item ID is {}, instance ID is {}, skipping", itemId, instanceId);
return null;
}
- // check if circulation item already exists
+ // Check if circulation item already exists in the tenant we want to create it in
CirculationItem existingCirculationItem = circulationItemClient.getCirculationItem(itemId);
if (existingCirculationItem != null) {
- log.info("createCirculationItem:: circulation item already exists");
+ log.info("createCirculationItem:: circulation item already exists in status '{}'",
+ Optional.ofNullable(existingCirculationItem.getStatus())
+ .map(CirculationItemStatus::getName)
+ .map(CirculationItemStatus.NameEnum::getValue)
+ .orElse(null));
return existingCirculationItem;
}
- InventoryItem item = getItemFromStorage(itemId, lendingTenantId);
- InventoryInstance instance = getInstanceFromStorage(instanceId, lendingTenantId);
+ InventoryItem item = getItemFromStorage(itemId, inventoryTenantId);
+ InventoryInstance instance = getInstanceFromStorage(instanceId, inventoryTenantId);
var itemStatus = item.getStatus().getName();
var circulationItemStatus = CirculationItemStatus.NameEnum.fromValue(itemStatus.getValue());
@@ -166,32 +230,28 @@ public CirculationItem createCirculationItem(EcsTlrEntity ecsTlr, Request second
.permanentLoanTypeId(item.getPermanentLoanTypeId())
.instanceTitle(instance.getTitle())
.barcode(item.getBarcode())
- .pickupLocation(secondaryRequest.getPickupServicePointId())
+ .pickupLocation(pickupLocation)
.effectiveLocationId(item.getEffectiveLocationId())
.lendingLibraryCode("TEST_CODE");
- log.info("createCirculationItem:: Creating circulation item {}", circulationItem.toString());
-
+ log.info("createCirculationItem:: creating circulation item {}", circulationItem.toString());
return circulationItemClient.createCirculationItem(itemId, circulationItem);
}
@Override
public CirculationItem updateCirculationItemOnRequestCreation(CirculationItem circulationItem,
- Request secondaryRequest) {
+ Request request) {
if (circulationItem == null) {
log.info("updateCirculationItemOnRequestCreation:: circulation item is null, skipping");
return null;
}
-
log.info("updateCirculationItemOnRequestCreation:: updating circulation item {}",
circulationItem.getId());
- if (secondaryRequest.getRequestType() == Request.RequestTypeEnum.PAGE) {
- log.info("updateCirculationItemOnRequestCreation:: secondary request {} type is " +
- "Page, updating circulation item {} with status Paged", secondaryRequest.getId(),
- circulationItem.getId());
-
+ if (request.getRequestType() == Request.RequestTypeEnum.PAGE) {
+ log.info("updateCirculationItemOnRequestCreation:: request {} type is 'Page', " +
+ "updating circulation item {} with status 'Paged'", request.getId(), circulationItem.getId());
circulationItem.getStatus().setName(CirculationItemStatus.NameEnum.PAGED);
circulationItemClient.updateCirculationItem(circulationItem.getId().toString(),
circulationItem);
@@ -232,10 +292,13 @@ public Collection getRequestsFromStorage(CqlQuery query, String idIndex
log.info("getRequestsFromStorage:: searching requests by query and index: query={}, index={}, ids={}",
query, idIndex, ids.size());
log.debug("getRequestsFromStorage:: ids={}", ids);
+ return BulkFetcher.fetch(requestStorageClient, query, idIndex, ids, Requests::getRequests);
+ }
- Collection requests = BulkFetcher.fetch(requestStorageClient, query, idIndex, ids,
- Requests::getRequests);
-
+ @Override
+ public Collection getRequestsFromStorage(CqlQuery query) {
+ log.info("getRequestsFromStorage:: searching requests by query: {}", query);
+ Collection requests = requestStorageClient.getByQuery(query).getRequests();
log.info("getRequestsFromStorage:: found {} requests", requests::size);
return requests;
}
diff --git a/src/main/java/org/folio/service/impl/SearchSlipsService.java b/src/main/java/org/folio/service/impl/SearchSlipsService.java
new file mode 100644
index 00000000..a8156dfd
--- /dev/null
+++ b/src/main/java/org/folio/service/impl/SearchSlipsService.java
@@ -0,0 +1,50 @@
+package org.folio.service.impl;
+
+import static org.folio.domain.dto.ItemStatus.NameEnum.AWAITING_DELIVERY;
+import static org.folio.domain.dto.ItemStatus.NameEnum.CHECKED_OUT;
+import static org.folio.domain.dto.ItemStatus.NameEnum.IN_PROCESS;
+import static org.folio.domain.dto.ItemStatus.NameEnum.IN_TRANSIT;
+import static org.folio.domain.dto.ItemStatus.NameEnum.MISSING;
+import static org.folio.domain.dto.ItemStatus.NameEnum.ON_ORDER;
+import static org.folio.domain.dto.ItemStatus.NameEnum.PAGED;
+import static org.folio.domain.dto.ItemStatus.NameEnum.RESTRICTED;
+import static org.folio.domain.dto.Request.RequestTypeEnum.HOLD;
+import static org.folio.domain.dto.Request.StatusEnum.OPEN_NOT_YET_FILLED;
+
+import java.util.EnumSet;
+
+import org.folio.domain.dto.ItemStatus;
+import org.folio.service.AddressTypeService;
+import org.folio.service.ConsortiaService;
+import org.folio.service.DepartmentService;
+import org.folio.service.InventoryService;
+import org.folio.service.LocationService;
+import org.folio.service.RequestService;
+import org.folio.service.ServicePointService;
+import org.folio.service.UserGroupService;
+import org.folio.service.UserService;
+import org.folio.spring.service.SystemUserScopedExecutionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import lombok.extern.log4j.Log4j2;
+
+@Service
+@Log4j2
+public class SearchSlipsService extends StaffSlipsServiceImpl {
+
+ private static final EnumSet ITEM_STATUSES = EnumSet.of(
+ CHECKED_OUT, AWAITING_DELIVERY, IN_TRANSIT, MISSING, PAGED, ON_ORDER, IN_PROCESS, RESTRICTED);
+
+ @Autowired
+ public SearchSlipsService(LocationService locationService, InventoryService inventoryService,
+ RequestService requestService, ConsortiaService consortiaService,
+ SystemUserScopedExecutionService executionService, UserService userService,
+ UserGroupService userGroupService, DepartmentService departmentService,
+ AddressTypeService addressTypeService, ServicePointService servicePointService) {
+
+ super(ITEM_STATUSES, EnumSet.of(OPEN_NOT_YET_FILLED), EnumSet.of(HOLD), locationService,
+ inventoryService, requestService, consortiaService, executionService, userService,
+ userGroupService, departmentService, addressTypeService, servicePointService);
+ }
+}
diff --git a/src/main/java/org/folio/service/impl/StaffSlipsServiceImpl.java b/src/main/java/org/folio/service/impl/StaffSlipsServiceImpl.java
index 2ec7fc89..f43b8323 100644
--- a/src/main/java/org/folio/service/impl/StaffSlipsServiceImpl.java
+++ b/src/main/java/org/folio/service/impl/StaffSlipsServiceImpl.java
@@ -1,23 +1,27 @@
package org.folio.service.impl;
+import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
import static java.util.Locale.getISOCountries;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.mapping;
+import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang3.StringUtils.firstNonBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.folio.domain.dto.Request.RequestLevelEnum.TITLE;
+import static org.folio.domain.dto.Request.RequestTypeEnum.HOLD;
-import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -30,8 +34,10 @@
import org.folio.domain.dto.AddressType;
import org.folio.domain.dto.Campus;
-import org.folio.domain.dto.Contributor;
import org.folio.domain.dto.Department;
+import org.folio.domain.dto.HoldingsRecord;
+import org.folio.domain.dto.Instance;
+import org.folio.domain.dto.InstanceContributorsInner;
import org.folio.domain.dto.Institution;
import org.folio.domain.dto.Item;
import org.folio.domain.dto.ItemEffectiveCallNumberComponents;
@@ -41,9 +47,6 @@
import org.folio.domain.dto.Location;
import org.folio.domain.dto.MaterialType;
import org.folio.domain.dto.Request;
-import org.folio.domain.dto.SearchHolding;
-import org.folio.domain.dto.SearchInstance;
-import org.folio.domain.dto.SearchItem;
import org.folio.domain.dto.ServicePoint;
import org.folio.domain.dto.StaffSlip;
import org.folio.domain.dto.StaffSlipItem;
@@ -60,7 +63,6 @@
import org.folio.service.InventoryService;
import org.folio.service.LocationService;
import org.folio.service.RequestService;
-import org.folio.service.SearchService;
import org.folio.service.ServicePointService;
import org.folio.service.StaffSlipsService;
import org.folio.service.UserGroupService;
@@ -68,7 +70,9 @@
import org.folio.spring.service.SystemUserScopedExecutionService;
import org.folio.support.CqlQuery;
+import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import lombok.Setter;
import lombok.extern.log4j.Log4j2;
@RequiredArgsConstructor
@@ -88,39 +92,82 @@ public class StaffSlipsServiceImpl implements StaffSlipsService {
private final UserGroupService userGroupService;
private final DepartmentService departmentService;
private final AddressTypeService addressTypeService;
- private final SearchService searchService;
private final ServicePointService servicePointService;
@Override
public Collection getStaffSlips(String servicePointId) {
log.info("getStaffSlips:: building staff slips for service point {}", servicePointId);
+ StaffSlipsContext context = new StaffSlipsContext();
+ findLocationsAndItems(servicePointId, context);
+ if (context.getLocationsByTenant().isEmpty()) {
+ log.info("getStaffSlips:: found no location for service point {}, doing nothing", servicePointId);
+ return emptyList();
+ }
+ findRequests(context);
+ if (context.getRequests().isEmpty()) {
+ log.info("getStaffSlips:: found no requests to build staff slips for, doing nothing");
+ return emptyList();
+ }
+ discardNonRequestedItems(context);
+ findInstances(context);
+ findRequesters(context);
+ findUserGroups(context);
+ findDepartments(context);
+ findAddressTypes(context);
+ findPickupServicePoints(context);
+ fetchDataFromLendingTenants(context);
+
+ Collection staffSlips = buildStaffSlips(context);
+ log.info("getStaffSlips:: successfully built {} staff slips", staffSlips::size);
+ return staffSlips;
+ }
+
+ private void findHoldRequestsWithoutItems(StaffSlipsContext context) {
+ if (!relevantRequestTypes.contains(HOLD)) {
+ log.info("findHoldRequestsWithoutItems:: 'Hold' is not a relevant request type, doing nothing");
+ return;
+ }
+
+ Collection holdRequestsWithoutItems = findTitleLevelHoldsWithoutItems();
+ Collection instances = findInstancesForRequests(holdRequestsWithoutItems);
+ Map> holdings = findHoldingsForHolds(instances, context);
- Map> locationsByTenant = findLocations(servicePointId);
- Collection locationIds = locationsByTenant.values()
+ Set relevantInstanceIds = holdings.values()
.stream()
.flatMap(Collection::stream)
- .map(Location::getId)
+ .map(HoldingsRecord::getInstanceId)
.collect(toSet());
- Collection instances = findInstances(locationIds);
- Collection itemsInRelevantLocations = getItemsForLocations(instances, locationIds);
- Collection requests = findRequests(itemsInRelevantLocations);
- Collection requestedItems = filterRequestedItems(itemsInRelevantLocations, requests);
- Collection staffSlipContexts = buildStaffSlipContexts(requests, requestedItems,
- instances, locationsByTenant);
- Collection staffSlips = buildStaffSlips(staffSlipContexts);
+ List requestsForRelevantInstances = holdRequestsWithoutItems.stream()
+ .filter(request -> relevantInstanceIds.contains(request.getInstanceId()))
+ .toList();
- log.info("getStaffSlips:: successfully built {} staff slips", staffSlips::size);
- return staffSlips;
+ log.info("getStaffSlips:: {} of {} hold requests are placed on relevant instances",
+ requestsForRelevantInstances::size, holdRequestsWithoutItems::size);
+
+ context.getRequests().addAll(requestsForRelevantInstances);
+ context.getInstanceCache().addAll(instances);
}
- private Map> findLocations(String servicePointId) {
- log.info("findLocations:: searching for locations in all consortium tenants");
- CqlQuery query = CqlQuery.exactMatch("primaryServicePoint", servicePointId);
+ private void findLocationsAndItems(String servicePointId, StaffSlipsContext staffSlipsContext) {
+ CqlQuery locationsQuery = CqlQuery.exactMatch("primaryServicePoint", servicePointId);
- return getAllConsortiumTenants()
- .stream()
- .collect(toMap(identity(), tenantId -> findLocations(query, tenantId)));
+ getAllConsortiumTenants()
+ .forEach(tenantId -> executionService.executeSystemUserScoped(tenantId, () -> {
+ log.info("getStaffSlips:: searching for relevant locations and items in tenant {}", tenantId);
+ Collection locations = locationService.findLocations(locationsQuery);
+ Map locationsById = toMapById(locations, Location::getId);
+
+ Collection
- items = findItems(locations);
+ Collection itemContexts = items.stream()
+ .map(item -> new ItemContext(item.getId(), item,
+ locationsById.get(item.getEffectiveLocationId())))
+ .collect(toList());
+
+ staffSlipsContext.getLocationsByTenant().put(tenantId, locations);
+ staffSlipsContext.getItemContextsByTenant().put(tenantId, itemContexts);
+ return null;
+ }));
}
private Collection getAllConsortiumTenants() {
@@ -130,317 +177,279 @@ private Collection getAllConsortiumTenants() {
.collect(toSet());
}
- private Collection findLocations(CqlQuery query, String tenantId) {
- log.info("findLocations:: searching for locations in tenant {} by query: {}", tenantId, query);
- return executionService.executeSystemUserScoped(tenantId, () -> locationService.findLocations(query));
- }
-
- private Collection findInstances(Collection locationIds) {
- log.info("findInstances:: searching for instances");
- if (locationIds.isEmpty()) {
- log.info("findItems:: no locations to search instances for, doing nothing");
+ private Collection
- findItems(Collection locations) {
+ if (locations.isEmpty()) {
+ log.info("findItems:: no locations to search items for, doing nothing");
return emptyList();
}
- List itemStatusStrings = relevantItemStatuses.stream()
+ Set locationIds = locations.stream()
+ .map(Location::getId)
+ .collect(toSet());
+
+ Set itemStatuses = relevantItemStatuses.stream()
.map(ItemStatus.NameEnum::getValue)
- .toList();
+ .collect(toSet());
- CqlQuery query = CqlQuery.exactMatchAny("item.status.name", itemStatusStrings);
+ CqlQuery query = CqlQuery.exactMatchAny("status.name", itemStatuses);
- return searchService.searchInstances(query, "item.effectiveLocationId", locationIds);
+ return inventoryService.findItems(query, "effectiveLocationId", locationIds);
}
- private static Collection getItemsForLocations(Collection instances,
- Collection locationIds) {
+ private void findRequests(StaffSlipsContext context) {
+ log.info("findRequestsForItems:: searching for requests for relevant items");
- log.info("getItemsForLocations:: searching for items in relevant locations");
- List items = instances.stream()
- .map(SearchInstance::getItems)
+ List itemIds = context.getItemContextsByTenant()
+ .values()
+ .stream()
.flatMap(Collection::stream)
- .filter(item -> locationIds.contains(item.getEffectiveLocationId()))
+ .map(ItemContext::getItem)
+ .map(Item::getId)
.toList();
- log.info("getItemsForLocations:: found {} items in relevant locations", items::size);
- return items;
- }
-
- private Collection findRequests(Collection items) {
- log.info("findRequests:: searching for requests for relevant items");
- if (items.isEmpty()) {
- log.info("findRequests:: no items to search requests for, doing nothing");
- return emptyList();
+ if (itemIds.isEmpty()) {
+ log.info("findRequestsForItems:: no items to search requests for, doing nothing");
+ return;
}
- Set itemIds = items.stream()
- .map(SearchItem::getId)
- .collect(toSet());
-
List requestTypes = relevantRequestTypes.stream()
.map(Request.RequestTypeEnum::getValue)
- .toList();
+ .collect(toList());
List requestStatuses = relevantRequestStatuses.stream()
.map(Request.StatusEnum::getValue)
- .toList();
+ .collect(toList());
CqlQuery query = CqlQuery.exactMatchAny("requestType", requestTypes)
.and(CqlQuery.exactMatchAny("status", requestStatuses));
- return requestService.getRequestsFromStorage(query, "itemId", itemIds);
+ Collection requests = requestService.getRequestsFromStorage(query, "itemId", itemIds);
+ context.getRequests().addAll(requests);
+ findHoldRequestsWithoutItems(context);
}
- private static Collection filterRequestedItems(Collection items,
- Collection requests) {
-
- log.info("filterItemsByRequests:: filtering out non-requested items");
- Set requestedItemIds = requests.stream()
- .map(Request::getItemId)
- .filter(Objects::nonNull)
- .collect(toSet());
+ private Collection findTitleLevelHoldsWithoutItems() {
+ log.info("findHoldRequestsWithoutItem:: searching for open hold requests without itemId");
+ List requestStatuses = relevantRequestStatuses.stream()
+ .map(Request.StatusEnum::getValue)
+ .collect(toList());
- List requestedItems = items.stream()
- .filter(item -> requestedItemIds.contains(item.getId()))
- .toList();
+ CqlQuery query = CqlQuery.exactMatch("requestType", HOLD.getValue())
+ .and(CqlQuery.exactMatch("requestLevel", TITLE.getValue()))
+ .and(CqlQuery.exactMatchAny("status", requestStatuses))
+ .not(CqlQuery.match("itemId", ""));
- log.info("filterItemsByRequests:: {} of {} relevant items are requested", requestedItems::size,
- items::size);
- return requestedItems;
+ return requestService.getRequestsFromStorage(query);
}
- private Collection buildStaffSlipContexts(Collection requests,
- Collection requestedItems, Collection instances,
- Map> locationsByTenant) {
+ private Map> findHoldingsForHolds(Collection instances,
+ StaffSlipsContext context) {
- if (requests.isEmpty()) {
- log.info("buildStaffSlipContexts:: no requests to build contexts for, doing nothing");
- return emptyList();
+ log.info("findHoldingsForHolds:: searching holdings for instances");
+
+ if (instances.isEmpty()) {
+ log.info("findHoldingsForHolds:: no instances to search holdings for, doing nothing");
+ return emptyMap();
}
- log.info("buildStaffSlipContexts:: building contexts for {} requests", requests::size);
- Map itemContextsByItemId = buildItemContexts(requestedItems, instances,
- locationsByTenant);
- Map requesterContextsByRequestId = buildRequesterContexts(requests);
- Map requestContextsByRequestId = buildRequestContexts(requests);
-
- Collection staffSlipContexts = requests.stream()
- .map(request -> new StaffSlipContext(
- itemContextsByItemId.get(request.getItemId()),
- requesterContextsByRequestId.get(request.getId()),
- requestContextsByRequestId.get(request.getId())))
- .toList();
+ Set instanceIds = instances.stream()
+ .map(Instance::getId)
+ .collect(toSet());
- log.info("getStaffSlips:: successfully built contexts for {} requests", requests::size);
- return staffSlipContexts;
+ return context.getLocationsByTenant()
+ .keySet()
+ .stream()
+ .collect(toMap(identity(), tenantId -> executionService.executeSystemUserScoped(tenantId,
+ () -> findHoldingsForHolds(instanceIds, context, tenantId))));
}
- private Map buildItemContexts(Collection requestedItems,
- Collection instances, Map> locationsByTenant) {
+ private Collection findHoldingsForHolds(Collection instanceIds,
+ StaffSlipsContext context, String tenantId) {
- log.info("buildItemContexts:: building contexts for {} items", requestedItems::size);
+ log.info("findHoldings:: searching holdings for relevant locations and instances");
- Map> requestedItemIdsByTenant = requestedItems.stream()
- .collect(groupingBy(SearchItem::getTenantId, mapping(SearchItem::getId, toSet())));
+ Set relevantLocationIds = context.getLocationsByTenant()
+ .get(tenantId)
+ .stream()
+ .map(Location::getId)
+ .collect(toSet());
- Map itemIdToInstance = instances.stream()
- .flatMap(searchInstance -> searchInstance.getItems().stream()
- .map(item -> new AbstractMap.SimpleEntry<>(item.getId(), searchInstance)))
- .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
+ if (relevantLocationIds.isEmpty()) {
+ log.info("findHoldings:: no location to search holdings for, doing nothing");
+ return emptyList();
+ }
- return requestedItemIdsByTenant.entrySet()
- .stream()
- .map(entry -> buildItemContexts(entry.getKey(), entry.getValue(), locationsByTenant, itemIdToInstance))
- .flatMap(Collection::stream)
- .collect(toMap(context -> context.item().getId(), identity()));
- }
+ if (instanceIds.isEmpty()) {
+ log.info("findHoldings:: no instances to search holdings for, doing nothing");
+ return emptyList();
+ }
+
+ Collection holdingsForInstances = inventoryService.findHoldings(CqlQuery.empty(),
+ "instanceId", instanceIds);
- private Collection buildItemContexts(String tenantId, Collection itemIds,
- Map> locationsByTenant, Map itemIdToInstance) {
+ log.info("findHoldingsForHolds:: caching {} holdings", holdingsForInstances::size);
+ context.getHoldingsByIdCache().put(tenantId, holdingsForInstances);
- log.info("buildItemContexts:: building item contexts for {} items in tenant {}", itemIds.size(), tenantId);
- return executionService.executeSystemUserScoped(tenantId,
- () -> buildItemContexts(itemIds, itemIdToInstance, locationsByTenant.get(tenantId)));
+ List holdingsInRelevantLocations = holdingsForInstances.stream()
+ .filter(holding -> relevantLocationIds.contains(holding.getEffectiveLocationId()))
+ .collect(toList());
+
+ log.info("findHoldings:: {} of {} holdings are in relevant locations",
+ holdingsInRelevantLocations::size, holdingsForInstances::size);
+
+ return holdingsInRelevantLocations;
}
- private Collection buildItemContexts(Collection itemIds,
- Map itemIdToInstance, Collection locations) {
+ private void findHoldings(StaffSlipsContext context, String tenantId) {
+ log.info("findHoldings:: searching holdings");
- Collection
- items = inventoryService.findItems(itemIds);
+ Collection itemContexts = context.getItemContextsByTenant().get(tenantId);
+ Set requestedHoldingIds = itemContexts.stream()
+ .map(ItemContext::getItem)
+ .map(Item::getHoldingsRecordId)
+ .collect(toSet());
- Map materialTypesById = findMaterialTypes(items)
+ Map cachedHoldingsById = context.getHoldingsByIdCache()
+ .getOrDefault(tenantId, new ArrayList<>())
.stream()
- .collect(mapById(MaterialType::getId));
+ .collect(mapById(HoldingsRecord::getId));
+
+ Set missingHoldingIds = new HashSet<>(requestedHoldingIds);
+ missingHoldingIds.removeAll(cachedHoldingsById.keySet());
+
+ log.info("findHoldings:: cache hit for {} of {} requested holdings",
+ requestedHoldingIds.size() - missingHoldingIds.size(), requestedHoldingIds.size());
- Map loanTypesById = findLoanTypes(items)
+ Map fetchedHoldingsById = inventoryService.findHoldings(missingHoldingIds)
.stream()
- .collect(mapById(LoanType::getId));
+ .collect(mapById(HoldingsRecord::getId));
- Set locationIdsOfRequestedItems = items.stream()
- .map(Item::getEffectiveLocationId)
- .collect(toSet());
+ itemContexts.forEach(itemContext -> {
+ String holdingsRecordId = itemContext.getItem().getHoldingsRecordId();
+ Optional.ofNullable(cachedHoldingsById.get(holdingsRecordId))
+ .or(() -> Optional.ofNullable(fetchedHoldingsById.get(holdingsRecordId)))
+ .ifPresent(itemContext::setHolding);
+ });
- Map locationsById = locations.stream()
- .filter(location -> locationIdsOfRequestedItems.contains(location.getId()))
- .toList().stream()
- .collect(mapById(Location::getId));
+ context.getInstanceCache().clear();
+ }
- Collection locationsOfRequestedItems = locationsById.values();
+ private Collection findInstancesForRequests(Collection requests) {
+ log.info("findInstances:: searching instances for requests");
+ if (requests.isEmpty()) {
+ log.info("findInstances:: no requests to search instances for, doing nothing");
+ return emptyList();
+ }
- Map librariesById = findLibraries(locationsOfRequestedItems)
- .stream()
- .collect(mapById(Library::getId));
+ Set instanceIds = requests.stream()
+ .map(Request::getInstanceId)
+ .collect(toSet());
- Map campusesById = findCampuses(locationsOfRequestedItems)
- .stream()
- .collect(mapById(Campus::getId));
+ return inventoryService.findInstances(instanceIds);
+ }
- Map institutionsById = findInstitutions(locationsOfRequestedItems)
+ private void findInstances(StaffSlipsContext context) {
+ log.info("findInstances:: searching instances");
+ Set requestedInstanceIds = context.getRequests()
.stream()
- .collect(mapById(Institution::getId));
+ .map(Request::getInstanceId)
+ .collect(toSet());
- Map servicePointsById = findServicePointsForLocations(locationsOfRequestedItems)
+ Map cachedRequestedInstancesById = context.getInstanceCache()
.stream()
- .collect(mapById(ServicePoint::getId));
-
- List itemContexts = new ArrayList<>(items.size());
- for (Item item : items) {
- SearchInstance instance = itemIdToInstance.get(item.getId());
- Location location = locationsById.get(item.getEffectiveLocationId());
- ServicePoint primaryServicePoint = Optional.ofNullable(location.getPrimaryServicePoint())
- .map(UUID::toString)
- .map(servicePointsById::get)
- .orElse(null);
- SearchHolding holding = instance.getHoldings()
- .stream()
- .filter(h -> item.getHoldingsRecordId().equals(h.getId()))
- .findFirst()
- .orElse(null);
-
- ItemContext itemContext = new ItemContext(item, instance, holding, location,
- materialTypesById.get(item.getMaterialTypeId()),
- loanTypesById.get(getEffectiveLoanTypeId(item)),
- institutionsById.get(location.getInstitutionId()),
- campusesById.get(location.getCampusId()),
- librariesById.get(location.getLibraryId()),
- primaryServicePoint);
-
- itemContexts.add(itemContext);
- }
+ .filter(instance -> requestedInstanceIds.contains(instance.getId()))
+ .collect(mapById(Instance::getId));
- return itemContexts;
- }
-
- private Map buildRequesterContexts(Collection requests) {
- log.info("buildRequesterContexts:: building requester contexts for {} requests", requests::size);
- Collection requesters = findRequesters(requests);
- Collection userGroups = findUserGroups(requesters);
- Collection departments = findDepartments(requesters);
- Collection addressTypes = findAddressTypes(requesters);
-
- Map requestersById = requesters.stream()
- .collect(mapById(User::getId));
- Map userGroupsById = userGroups.stream()
- .collect(mapById(UserGroup::getId));
- Map departmentsById = departments.stream()
- .collect(mapById(Department::getId));
- Map addressTypesById = addressTypes.stream()
- .collect(mapById(AddressType::getId));
-
- Map requesterContexts = new HashMap<>(requests.size());
- for (Request request : requests) {
- User requester = requestersById.get(request.getRequesterId());
- UserGroup userGroup = userGroupsById.get(requester.getPatronGroup());
-
- Collection requesterDepartments = requester.getDepartments()
- .stream()
- .filter(Objects::nonNull)
- .map(departmentsById::get)
- .toList();
-
- AddressType primaryRequesterAddressType = Optional.ofNullable(requester.getPersonal())
- .map(UserPersonal::getAddresses)
- .flatMap(addresses -> addresses.stream()
- .filter(UserPersonalAddressesInner::getPrimaryAddress)
- .findFirst()
- .map(UserPersonalAddressesInner::getAddressTypeId)
- .map(addressTypesById::get))
- .orElse(null);
+ Set missingInstanceIds = new HashSet<>(requestedInstanceIds);
+ missingInstanceIds.removeAll(cachedRequestedInstancesById.keySet());
- AddressType deliveryAddressType = addressTypesById.get(request.getDeliveryAddressTypeId());
+ log.info("findInstances:: cache hit for {} of {} requested instances",
+ requestedInstanceIds.size() - missingInstanceIds.size(), requestedInstanceIds.size());
- RequesterContext requesterContext = new RequesterContext(requester, userGroup,
- requesterDepartments, primaryRequesterAddressType, deliveryAddressType);
- requesterContexts.put(request.getId(), requesterContext);
- }
+ Map fetchedInstancesById = inventoryService.findInstances(missingInstanceIds)
+ .stream()
+ .collect(mapById(Instance::getId));
- return requesterContexts;
+ context.getInstancesById().putAll(fetchedInstancesById);
+ context.getInstancesById().putAll(cachedRequestedInstancesById);
+ context.getInstanceCache().clear();
}
- private Map buildRequestContexts(Collection requests) {
- log.info("buildRequesterContexts:: building request contexts for {} requests", requests::size);
- Collection servicePoints = findServicePointsForRequests(requests);
- Map servicePointsById = servicePoints.stream()
- .collect(mapById(ServicePoint::getId));
-
- Map requestContexts = new HashMap<>(requests.size());
- for (Request request : requests) {
- ServicePoint pickupServicePoint = servicePointsById.get(request.getPickupServicePointId());
- RequestContext requestContext = new RequestContext(request, pickupServicePoint);
- requestContexts.put(request.getId(), requestContext);
- }
+ private void fetchDataFromLendingTenants(StaffSlipsContext context) {
+ context.getItemContextsByTenant()
+ .keySet()
+ .forEach(tenantId -> executionService.executeSystemUserScoped(tenantId,
+ () -> fetchDataFromLendingTenant(context, tenantId)));
+ }
- return requestContexts;
+ private StaffSlipsContext fetchDataFromLendingTenant(StaffSlipsContext context, String tenantId) {
+ log.info("fetchDataFromLendingTenant:: fetching item-related data from tenant {}", tenantId);
+ Collection itemContexts = context.getItemContextsByTenant().get(tenantId);
+ findHoldings(context, tenantId);
+ findMaterialTypes(itemContexts);
+ findLoanTypes(itemContexts);
+ findLibraries(itemContexts);
+ findCampuses(itemContexts);
+ findInstitutions(itemContexts);
+ findPrimaryServicePoints(itemContexts);
+ return context;
}
- private Collection findRequesters(Collection requests) {
- if (requests.isEmpty()) {
+ private void findRequesters(StaffSlipsContext context) {
+ if (context.getRequests().isEmpty()) {
log.info("findRequesters:: no requests to search requesters for, doing nothing");
- return emptyList();
+ return;
}
- Set requesterIds = requests.stream()
+ Set requesterIds = context.getRequests().stream()
.map(Request::getRequesterId)
.collect(toSet());
- return userService.find(requesterIds);
+ Collection users = userService.find(requesterIds);
+ context.getRequestersById().putAll(toMapById(users, User::getId));
}
- private Collection findUserGroups(Collection requesters) {
- if (requesters.isEmpty()) {
+ private void findUserGroups(StaffSlipsContext context) {
+ if (context.getRequestersById().isEmpty()) {
log.info("findUserGroups:: no requesters to search user groups for, doing nothing");
- return emptyList();
+ return;
}
- Set userGroupIds = requesters.stream()
+ Set userGroupIds = context.getRequestersById().values()
+ .stream()
.map(User::getPatronGroup)
.filter(Objects::nonNull)
.collect(toSet());
- return userGroupService.find(userGroupIds);
+ Collection userGroups = userGroupService.find(userGroupIds);
+ context.getUserGroupsById().putAll(toMapById(userGroups, UserGroup::getId));
}
- private Collection findDepartments(Collection requesters) {
- if (requesters.isEmpty()) {
+ private void findDepartments(StaffSlipsContext context) {
+ if (context.getRequestersById().isEmpty()) {
log.info("findDepartments:: no requesters to search departments for, doing nothing");
- return emptyList();
+ return;
}
- Set departmentIds = requesters.stream()
+ Set departmentIds = context.getRequestersById().values()
+ .stream()
.map(User::getDepartments)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.collect(toSet());
- return departmentService.findDepartments(departmentIds);
+ Collection departments = departmentService.findDepartments(departmentIds);
+ context.getDepartmentsById().putAll(toMapById(departments, Department::getId));
}
- private Collection findAddressTypes(Collection requesters) {
- if (requesters.isEmpty()) {
+ private void findAddressTypes(StaffSlipsContext context) {
+ if (context.getRequestersById().isEmpty()) {
log.info("findAddressTypes:: no requesters to search address types for, doing nothing");
- return emptyList();
+ return;
}
- Set addressTypeIds = requesters.stream()
+ Set addressTypeIds = context.getRequestersById().values()
+ .stream()
.map(User::getPersonal)
.filter(Objects::nonNull)
.map(UserPersonal::getAddresses)
@@ -449,26 +458,24 @@ private Collection findAddressTypes(Collection requesters) {
.map(UserPersonalAddressesInner::getAddressTypeId)
.collect(toSet());
- return addressTypeService.findAddressTypes(addressTypeIds);
+ Collection addressTypes = addressTypeService.findAddressTypes(addressTypeIds);
+ context.getAddressTypesById().putAll(toMapById(addressTypes, AddressType::getId));
}
- private Collection findServicePointsForLocations(Collection locations) {
- return findServicePoints(
- locations.stream()
- .map(Location::getPrimaryServicePoint)
- .filter(Objects::nonNull)
- .map(UUID::toString)
- .collect(toSet())
- );
- }
+ private void findPickupServicePoints(StaffSlipsContext context) {
+ if ( context.getRequests().isEmpty()) {
+ log.info("findPickupServicePoints:: no requests to search service points for, doing nothing");
+ return;
+ }
- private Collection findServicePointsForRequests(Collection requests) {
- return findServicePoints(
- requests.stream()
- .map(Request::getPickupServicePointId)
- .filter(Objects::nonNull)
- .collect(toSet())
- );
+ Set pickupServicePointIds = context.getRequests()
+ .stream()
+ .map(Request::getPickupServicePointId)
+ .filter(Objects::nonNull)
+ .collect(toSet());
+
+ Collection pickupServicePoints = findServicePoints(pickupServicePointIds);
+ context.getPickupServicePointsById().putAll(toMapById(pickupServicePoints, ServicePoint::getId));
}
private Collection findServicePoints(Collection servicePointIds) {
@@ -480,111 +487,146 @@ private Collection findServicePoints(Collection servicePoi
return servicePointService.find(servicePointIds);
}
- private Collection findMaterialTypes(Collection
- items) {
- if (items.isEmpty()) {
+ private void findMaterialTypes(Collection itemContexts) {
+ if (itemContexts.isEmpty()) {
log.info("findMaterialTypes:: no items to search material types for, doing nothing");
- return emptyList();
+ return;
}
- Set materialTypeIds = items.stream()
- .map(Item::getMaterialTypeId)
- .collect(toSet());
+ Map> contextsByMaterialTypeId = itemContexts.stream()
+ .collect(groupingBy(context -> context.getItem().getMaterialTypeId()));
- return inventoryService.findMaterialTypes(materialTypeIds);
+ inventoryService.findMaterialTypes(contextsByMaterialTypeId.keySet())
+ .forEach(materialType -> contextsByMaterialTypeId.get(materialType.getId())
+ .forEach(context -> context.setMaterialType(materialType)));
}
- private Collection findLoanTypes(Collection
- items) {
- if (items.isEmpty()) {
+ private void findLoanTypes(Collection itemContexts) {
+ if (itemContexts.isEmpty()) {
log.info("findLoanTypes:: no items to search loan types for, doing nothing");
- return emptyList();
+ return;
}
- Set loanTypeIds = items.stream()
- .map(StaffSlipsServiceImpl::getEffectiveLoanTypeId)
- .collect(toSet());
+ Map> contextsByLoanTypeId = itemContexts.stream()
+ .collect(groupingBy(context -> getEffectiveLoanTypeId(context.getItem())));
- return inventoryService.findLoanTypes(loanTypeIds);
+ inventoryService.findLoanTypes(contextsByLoanTypeId.keySet())
+ .forEach(loanType -> contextsByLoanTypeId.get(loanType.getId())
+ .forEach(context -> context.setLoanType(loanType)));
}
- private Collection findLibraries(Collection