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

MCBFF-38: Update hardcoded effective location during checkin #47

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,13 @@
"circulation-bff.loans.check-in-by-barcode.execute"
],
"modulePermissions": [
"circulation.check-in-by-barcode.post"
"circulation.check-in-by-barcode.post",
"user-tenants.collection.get",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the same for item

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need user-tenants.item.get?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a rule that if we add a permission for an item, we need to add a similar one for the collection, and vice versa

Copy link
Contributor Author

@imerabishvili imerabishvili Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could not find user-tenants.item.get anywhere in folio-org. Does it exists?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right, it exists only for consortia.user-tenants.item.get, so ignore it then

"search.instances.collection.get",
"inventory-storage.items.item.get",
"inventory-storage.items.collection.get",
"inventory-storage.service-points.item.get",
"inventory-storage.service-points.collection.get"
]
}
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.folio.circulationbff.service;

import org.folio.circulationbff.domain.dto.Item;
import org.folio.circulationbff.domain.dto.ServicePoint;

public interface InventoryService {
Item fetchItem(String id);
ServicePoint fetchServicePoint(String id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import java.util.Collection;

import org.folio.circulationbff.domain.dto.BffSearchInstance;
import org.folio.circulationbff.domain.dto.SearchInstance;

public interface SearchService {
SearchInstance findInstanceByItemId(String itemId);
Collection<BffSearchInstance> findInstances(String query);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.folio.circulationbff.service;

public interface UserTenantsService {
String getCurrentTenant();
String getCentralTenant();
boolean isCentralTenant();
boolean isCentralTenant(String tenantId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,76 @@
package org.folio.circulationbff.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.folio.circulationbff.client.feign.CheckInClient;
import org.folio.circulationbff.domain.dto.CheckInRequest;
import org.folio.circulationbff.domain.dto.CheckInResponse;
import org.folio.circulationbff.domain.dto.SearchItem;
import org.folio.circulationbff.service.CheckInService;
import org.folio.circulationbff.service.InventoryService;
import org.folio.circulationbff.service.SearchService;
import org.folio.circulationbff.service.UserTenantsService;
import org.folio.spring.service.SystemUserScopedExecutionService;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import java.util.Objects;

@Service
@RequiredArgsConstructor
@Log4j2
public class CheckInServiceImpl implements CheckInService {

private final CheckInClient checkInClient;
private final SearchService searchService;
private final UserTenantsService userTenantsService;
private final InventoryService inventoryService;
private final SystemUserScopedExecutionService executionService;

@Override
public CheckInResponse checkIn(CheckInRequest request) {
log.info("checkIn: checking in item with barcode {} on service point {}",
request::getItemBarcode, request::getServicePointId);
return checkInClient.checkIn(request);
request.getItemBarcode(), request.getServicePointId());
var response = checkInClient.checkIn(request);
var item = response.getItem();
var servicePointName = getEffectiveLocationServicePoint(item.getId());
if (servicePointName != null) {
var slipContextItem = response.getStaffSlipContext().getItem();
slipContextItem.setEffectiveLocationPrimaryServicePointName(servicePointName);
slipContextItem.toServicePoint(servicePointName);
}
return response;
}

private String getEffectiveLocationServicePoint(String itemId) {
log.info("getEffectiveLocationServicePoint: itemId {}", itemId);
var instance = searchService.findInstanceByItemId(itemId);
if (instance == null) {
log.warn("getEffectiveLocationServicePoint: instance not found");
return null;
}
var itemTenantId = instance.getItems()
.stream()
.filter(item -> item.getId().equals(itemId))
.findFirst()
.map(SearchItem::getTenantId)
.orElse(null);
if (Objects.equals(itemTenantId, userTenantsService.getCurrentTenant())) {
log.info("getEffectiveLocationServicePoint: same tenant case {}", itemTenantId);
var item = inventoryService.fetchItem(itemId);
var servicePoint = inventoryService.fetchServicePoint(item.getEffectiveLocationId());
return servicePoint.getName();
} else {
log.info("getEffectiveLocationServicePoint: cross tenant case {}", itemTenantId);
var item = executionService.executeSystemUserScoped(
itemTenantId,
() -> inventoryService.fetchItem(itemId)
);
var servicePoint = executionService.executeSystemUserScoped(
itemTenantId,
() -> inventoryService.fetchServicePoint(item.getEffectiveLocationId())
);
return servicePoint.getName();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,39 +52,65 @@ public SearchSlipCollection fetchSearchSlipsByServicePointId(String servicePoint
@Override
public AllowedServicePoints getAllowedServicePoints(AllowedServicePointParams params, String tenantId) {
log.info("getAllowedServicePoints:: params: {}", params);
if (settingsService.isEcsTlrFeatureEnabled()) {
if (userTenantsService.isCentralTenant()) {
log.info("getAllowedServicePoints:: Ecs TLR Feature is enabled and we are in the central " +
"tenant. Calling local mod-tlr.");
return ecsTlrClient.getAllowedServicePoints(params);
} else {
if (params.getRequestId() == null) {
log.info("getAllowedServicePoints:: Ecs TLR Feature is enabled, requestId param is " +
"missing. Calling local mod-circulation.");
return circulationClient.allowedServicePoints(params);
} else {
var request = circulationClient.getRequestById(params.getRequestId().toString());
if (request.getEcsRequestPhase() == null) {
log.info("getAllowedServicePoints:: Ecs TLR Feature is enabled, but request is not " +
"an ECS request. Calling local mod-circulation.");
return circulationClient.allowedServicePoints(params);
} else {
log.info("getAllowedServicePoints:: Ecs TLR Feature is enabled and request is " +
"an ECS request. Calling central mod-tlr.");
String patronGroupId = params.getRequesterId() == null ? null :
userService.find(params.getRequesterId().toString()).getPatronGroup();
params.setPatronGroupId(patronGroupId != null ? UUID.fromString(patronGroupId) : null);
params.setRequesterId(null);
return executionService.executeSystemUserScoped(userTenantsService.getCentralTenant(),
() -> ecsTlrClient.getAllowedServicePoints(params));
}
}
}
} else {

if (!settingsService.isEcsTlrFeatureEnabled()) {
log.info("getAllowedServicePoints:: Ecs TLR Feature is disabled. " +
"Calling local mod-circulation.");
return circulationClient.allowedServicePoints(params);
}

if (userTenantsService.isCentralTenant()) {
log.info("getAllowedServicePoints:: Ecs TLR Feature is enabled and we are in the central " +
"tenant. Calling local mod-tlr.");
return ecsTlrClient.getAllowedServicePoints(params);
}

log.info("getAllowedServicePoints:: Ecs TLR Feature is enabled and current tenant is not " +
"central.");

if (params.getRequestId() == null) {
// log.info("getAllowedServicePoints:: Request ID is missing (creation).");
// if (params.getItemId() != null) {
// log.info("getAllowedServicePoints:: Item ID is present (ILR).");
// // Trying to fetch item to detect Mediated request creation case
// Item item = itemStorageClient.findItem(params.getItemId().toString());
// if (item == null) {
// log.info("getAllowedServicePoints:: Item not found in the current tenant. " +
// "Calling central mod-tlr.");
// return getAllowedSpFromCentralTlr(params);
// }
// }
// log.info("getAllowedServicePoints:: Item ID is either missing (TLR) or present and item " +
// "found locally. Calling local mod-circulation");
// return circulationClient.allowedServicePoints(params);

log.info("getAllowedServicePoints:: Request ID is missing (creation). Calling central mod-tlr.");
// This should handle both mediated request and local data tenant request cases.
// In case of a local request, central mod-tlr should call mod-circulation of the current
// data tenant anyway.
return getAllowedSpFromCentralTlr(params);
}

log.info("getAllowedServicePoints:: Request ID is present (editing).");

var request = circulationClient.getRequestById(params.getRequestId().toString());
if (request.getEcsRequestPhase() == null) {
log.info("getAllowedServicePoints:: Request is not an ECS request. Calling local mod-circulation.");
return circulationClient.allowedServicePoints(params);
}

log.info("getAllowedServicePoints:: Ecs TLR Feature is enabled and request is " +
"an ECS request. Calling central mod-tlr.");
return getAllowedSpFromCentralTlr(params);
}

private AllowedServicePoints getAllowedSpFromCentralTlr(AllowedServicePointParams params) {
String patronGroupId = params.getRequesterId() == null ? null :
userService.find(params.getRequesterId().toString()).getPatronGroup();
params.setPatronGroupId(patronGroupId != null ? UUID.fromString(patronGroupId) : null);
params.setRequesterId(null);
return executionService.executeSystemUserScoped(userTenantsService.getCentralTenant(),
() -> ecsTlrClient.getAllowedServicePoints(params));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.folio.circulationbff.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.folio.circulationbff.client.feign.ItemStorageClient;
import org.folio.circulationbff.client.feign.ServicePointClient;
import org.folio.circulationbff.domain.dto.Item;
import org.folio.circulationbff.domain.dto.ServicePoint;
import org.folio.circulationbff.service.InventoryService;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
@Log4j2
public class InventoryServiceImpl implements InventoryService {
private final ItemStorageClient itemClient;
private final ServicePointClient servicePointClient;

@Override
public Item fetchItem(String id) {
log.info("fetchItem:: fetching item {}", id);
return itemClient.findItem(id);
}

@Override
public ServicePoint fetchServicePoint(String id) {
log.info("fetchServicePoint:: fetching service point {}", id);
return servicePointClient.findServicePoint(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.folio.circulationbff.client.feign.HoldingsStorageClient;
import org.folio.circulationbff.client.feign.InstanceStorageClient;
Expand Down Expand Up @@ -71,6 +72,17 @@ public class SearchServiceImpl implements SearchService {
private final BulkFetchingService fetchingService;
private final SearchInstanceMapper searchInstanceMapper;

@Override
public SearchInstance findInstanceByItemId(String itemId) {
log.info("findInstanceByItemId:: itemId {}", itemId);
String query = "items.id==" + itemId;
SearchInstances searchResult = searchClient.findInstances(query, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SearchInstances searchResult = searchClient.findInstances(query, true);
SearchInstances searchInstances = searchClient.findInstances(query, true);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

if (CollectionUtils.isEmpty(searchResult.getInstances())) {
return null;
}
return searchResult.getInstances().get(0);
}

@Override
public Collection<BffSearchInstance> findInstances(String query) {
log.info("findInstances:: searching instances by query: {}", query);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.folio.circulationbff.service.impl;

import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.folio.circulationbff.client.feign.UserTenantsClient;
import org.folio.circulationbff.domain.dto.UserTenant;
import org.folio.circulationbff.domain.dto.UserTenantCollection;
Expand All @@ -18,11 +17,21 @@ public class UserTenantsServiceImpl implements UserTenantsService {

private final UserTenantsClient userTenantsClient;

@Override
public String getCurrentTenant() {
UserTenant firstUserTenant = getFirstUserTenant();
if (firstUserTenant == null) {
return null;
}
String currentTenantId = firstUserTenant.getTenantId();
log.info("getCurrentTenant:: currentTenantId={}", currentTenantId);
return currentTenantId;
}

@Override
public String getCentralTenant() {
UserTenant firstUserTenant = getFirstUserTenant();
if (firstUserTenant == null) {
log.info("getCentralTenant:: failed to fetch user tenants");
return null;
}
String centralTenantId = firstUserTenant.getCentralTenantId();
Expand All @@ -34,7 +43,6 @@ public String getCentralTenant() {
public boolean isCentralTenant() {
UserTenant firstUserTenant = getFirstUserTenant();
if (firstUserTenant == null) {
log.info("isCentralTenant:: failed to fetch user tenants");
return false;
}
String centralTenantId = firstUserTenant.getCentralTenantId();
Expand All @@ -45,14 +53,6 @@ public boolean isCentralTenant() {
return centralTenantId.equals(tenantId);
}

private UserTenant getFirstUserTenant() {
UserTenant firstUserTenant = findFirstUserTenant();
if (firstUserTenant == null) {
log.info("processUserGroupEvent: Failed to get user-tenants info");
}
return firstUserTenant;
}

@Override
public boolean isCentralTenant(String tenantId) {
UserTenant firstUserTenant = getFirstUserTenant();
Expand All @@ -67,21 +67,16 @@ public boolean isCentralTenant(String tenantId) {
return false;
}

private UserTenant findFirstUserTenant() {
log.info("findFirstUserTenant:: finding first userTenant");
UserTenant firstUserTenant = null;
UserTenantCollection userTenantCollection = userTenantsClient.getUserTenants(1);
log.info("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection);
if (userTenantCollection != null) {
log.info("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection);
List<UserTenant> userTenants = userTenantCollection.getUserTenants();
if (!userTenants.isEmpty()) {
firstUserTenant = userTenants.get(0);
log.info("findFirstUserTenant:: found userTenant: {}", firstUserTenant);
}
private UserTenant getFirstUserTenant() {
log.info("getFirstUserTenant:: finding first userTenant");
UserTenantCollection userTenants = userTenantsClient.getUserTenants(1);
log.info("getFirstUserTenant:: userTenants: {}", () -> userTenants);
if (userTenants == null || CollectionUtils.isEmpty(userTenants.getUserTenants())) {
log.warn("getFirstUserTenant: failed to fetch user tenants");
return null;
}
log.info("findFirstUserTenant:: result: {}", firstUserTenant);
var firstUserTenant = userTenants.getUserTenants().get(0);
log.info("getFirstUserTenant:: result: {}", firstUserTenant);
return firstUserTenant;
}
}

Loading
Loading