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

[MODORDERS-1174] Filter pieces based on user affiliations #1017

Merged
merged 5 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion ramls/acq-models
Submodule acq-models updated 0 files
12 changes: 10 additions & 2 deletions src/main/java/org/folio/config/ApplicationConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.folio.service.caches.InventoryCache;
import org.folio.service.configuration.ConfigurationEntriesService;
import org.folio.service.consortium.ConsortiumConfigurationService;
import org.folio.service.consortium.ConsortiumUserTenantsRetriever;
import org.folio.service.consortium.SharingInstanceService;
import org.folio.service.exchange.ExchangeRateProviderResolver;
import org.folio.service.exchange.FinanceExchangeRateService;
Expand Down Expand Up @@ -521,8 +522,10 @@ PieceChangeReceiptStatusPublisher receiptStatusPublisher() {
}

@Bean
PieceStorageService pieceStorageService(RestClient restClient) {
return new PieceStorageService(restClient);
PieceStorageService pieceStorageService(ConsortiumConfigurationService consortiumConfigurationService,
ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever,
RestClient restClient) {
return new PieceStorageService(consortiumConfigurationService, consortiumUserTenantsRetriever, restClient);
}

@Bean
Expand Down Expand Up @@ -848,6 +851,11 @@ ConsortiumConfigurationService consortiumConfigurationService(RestClient restCli
return new ConsortiumConfigurationService(restClient);
}

@Bean
ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever(RestClient restClient) {
return new ConsortiumUserTenantsRetriever(restClient);
}

@Bean
SharingInstanceService sharingInstanceService(RestClient restClient) {
return new SharingInstanceService(restClient);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/folio/helper/BindHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private Future<Void> removeForbiddenEntities(Piece piece, RequestContext request

private Future<Void> clearTitleBindItemsIfNeeded(String titleId, String bindItemId, RequestContext requestContext) {
String query = String.format("titleId==%s and bindItemId==%s and isBound==true", titleId, bindItemId);
return pieceStorageService.getPieces(0, 0, query, requestContext)
return pieceStorageService.getAllPieces(query, requestContext)
SerhiiNosko marked this conversation as resolved.
Show resolved Hide resolved
.compose(pieceCollection -> {
var totalRecords = pieceCollection.getTotalRecords();
if (totalRecords != 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ private List<Piece> getSuccessfullyProcessedPieces(String poLineId, Map<String,

private Future<List<Piece>> getPiecesByPoLine(String poLineId, RequestContext requestContext) {
String query = String.format("poLineId==%s", poLineId);
return pieceStorageService.getPieces(Integer.MAX_VALUE, 0, query, requestContext)
return pieceStorageService.getAllPieces(query, requestContext)
.map(PieceCollection::getPieces);
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/folio/orders/utils/RequestContextUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ public static RequestContext createContextWithNewTenantId(RequestContext request
return new RequestContext(requestContext.getContext(), modifiedHeaders);
}

public static String getUserIdFromContext(RequestContext requestContext) {
return requestContext.getHeaders().get(XOkapiHeaders.USER_ID);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.util.Map;
import java.util.stream.Collectors;

import static org.folio.rest.RestConstants.PATH_PARAM_PLACE_HOLDER;

public class ResourcePathResolver {

private ResourcePathResolver() {
Expand Down Expand Up @@ -53,6 +55,8 @@ private ResourcePathResolver() {
public static final String ROUTING_LISTS = "routingLists";
public static final String ORDER_SETTINGS = "orderSettings";
public static final String USERS = "users";
public static final String CONSORTIA_USER_TENANTS = "consortia.user-tenants";


private static final Map<String, String> SUB_OBJECT_ITEM_APIS;
private static final Map<String, String> SUB_OBJECT_COLLECTION_APIS;
Expand Down Expand Up @@ -96,6 +100,7 @@ private ResourcePathResolver() {
apis.put(EXPORT_HISTORY, "/orders-storage/export-history");
apis.put(TAGS, "/tags");
apis.put(USERS, "/users");
apis.put(CONSORTIA_USER_TENANTS, "/consortia/" + PATH_PARAM_PLACE_HOLDER + "/user-tenants");
apis.put(ORDER_SETTINGS, "/orders-storage/settings");
apis.put(ROUTING_LISTS, "/orders-storage/routing-lists");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.folio.service.consortium;

import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;
import org.folio.rest.core.RestClient;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.core.models.RequestEntry;

import java.util.List;
import java.util.stream.IntStream;

import static org.folio.orders.utils.RequestContextUtil.getUserIdFromContext;
import static org.folio.orders.utils.ResourcePathResolver.CONSORTIA_USER_TENANTS;
import static org.folio.orders.utils.ResourcePathResolver.resourcesPath;
import static org.folio.rest.RestConstants.PATH_PARAM_PLACE_HOLDER;
import static org.folio.service.pieces.util.UserTenantFields.COLLECTION_USER_TENANTS;
import static org.folio.service.pieces.util.UserTenantFields.TENANT_ID;
import static org.folio.service.pieces.util.UserTenantFields.USER_ID;

public class ConsortiumUserTenantsRetriever {

private static final String CONSORTIA_USER_TENANTS_ENDPOINT = resourcesPath(CONSORTIA_USER_TENANTS);

private final RestClient restClient;

public ConsortiumUserTenantsRetriever(RestClient restClient) {
this.restClient = restClient;
}

public Future<List<String>> getUserTenants(String consortiumId, RequestContext requestContext) {
var userId = getUserIdFromContext(requestContext);
var url = CONSORTIA_USER_TENANTS_ENDPOINT.replace(PATH_PARAM_PLACE_HOLDER, consortiumId);
var requestEntry = new RequestEntry(url)
.withOffset(0)
.withLimit(Integer.MAX_VALUE)
.withQueryParameter(USER_ID.getValue(), userId);
return restClient.getAsJsonObject(requestEntry, requestContext)
.map(this::extractTenantIds);
}

private List<String> extractTenantIds(JsonObject userTenantCollection) {
var userTenants = userTenantCollection.getJsonArray(COLLECTION_USER_TENANTS.getValue());
return IntStream.range(0, userTenants.size())
.mapToObj(userTenants::getJsonObject)
.map(userTenant -> userTenant.getString(TENANT_ID.getValue()))
.toList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public Future<HoldingSummaryCollection> getHoldingsSummary(String holdingId, Req
var queryForPiece = String.format("?query=holdingId==%s", holdingId);
var queryForLines = String.format("?query=locations=\"holdingId\" : \"%s\"", holdingId);

return pieceStorageService.getPieces(Integer.MAX_VALUE, 0, queryForPiece, requestContext)
return pieceStorageService.getAllPieces(queryForPiece, requestContext)
.map(piecesCollection -> {
Set<String> lineIds = piecesCollection.getPieces().stream()
.map(Piece::getPoLineId)
Expand Down
46 changes: 38 additions & 8 deletions src/main/java/org/folio/service/pieces/PieceStorageService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.logging.log4j.LogManager;
Expand All @@ -24,6 +25,8 @@
import org.folio.rest.jaxrs.model.PieceCollection;

import io.vertx.core.Future;
import org.folio.service.consortium.ConsortiumUserTenantsRetriever;
import org.folio.service.consortium.ConsortiumConfigurationService;

public class PieceStorageService {
private static final Logger logger = LogManager.getLogger(PieceStorageService.class);
Expand All @@ -33,9 +36,15 @@ public class PieceStorageService {
private static final String PIECE_STORAGE_ENDPOINT = resourcesPath(PIECES_STORAGE);
private static final String PIECE_STORAGE_BY_ID_ENDPOINT = PIECE_STORAGE_ENDPOINT + "/{id}";

private final ConsortiumConfigurationService consortiumConfigurationService;
private final ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever;
private final RestClient restClient;

public PieceStorageService(RestClient restClient) {
public PieceStorageService(ConsortiumConfigurationService consortiumConfigurationService,
ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever,
RestClient restClient) {
this.consortiumConfigurationService = consortiumConfigurationService;
this.consortiumUserTenantsRetriever = consortiumUserTenantsRetriever;
this.restClient = restClient;
}

Expand Down Expand Up @@ -98,29 +107,50 @@ public Future<Void> deletePiecesByIds(List<String> pieceIds, RequestContext requ

public Future<PieceCollection> getExpectedPiecesByLineId(String poLineId, RequestContext requestContext) {
String query = String.format(PIECES_BY_POL_ID_AND_STATUS_QUERY, poLineId, Piece.ReceivingStatus.EXPECTED.value());
return getPieces(Integer.MAX_VALUE, 0, query, requestContext);
return getAllPieces(query, requestContext);
}

public Future<List<Piece>> getPiecesByHoldingId(String holdingId, RequestContext requestContext) {
if (holdingId != null) {
String query = String.format(PIECES_BY_HOLDING_ID_QUERY, holdingId);
return getPieces(Integer.MAX_VALUE, 0, query, requestContext).map(PieceCollection::getPieces);
return getAllPieces(query, requestContext).map(PieceCollection::getPieces);
}
return Future.succeededFuture(Collections.emptyList());
}

public Future<PieceCollection> getPieces(int limit, int offset, String query, RequestContext requestContext) {
RequestEntry requestEntry = new RequestEntry(PIECE_STORAGE_ENDPOINT).withQuery(query)
.withOffset(offset)
.withLimit(limit);
public Future<PieceCollection> getAllPieces(String query, RequestContext requestContext) {
var requestEntry = new RequestEntry(PIECE_STORAGE_ENDPOINT).withQuery(query).withOffset(0).withLimit(Integer.MAX_VALUE);
return restClient.get(requestEntry, PieceCollection.class, requestContext);
}

public Future<PieceCollection> getPieces(int limit, int offset, String query, RequestContext requestContext) {
var requestEntry = new RequestEntry(PIECE_STORAGE_ENDPOINT).withQuery(query).withOffset(offset).withLimit(limit);
return restClient.get(requestEntry, PieceCollection.class, requestContext)
.compose(piecesCollection -> filterPiecesByUserTenantsIfNecessary(piecesCollection.getPieces(), requestContext)
.map(piecesCollection::withPieces));
}

private Future<List<Piece>> filterPiecesByUserTenantsIfNecessary(List<Piece> pieces, RequestContext requestContext) {
return consortiumConfigurationService.getConsortiumConfiguration(requestContext)
.compose(consortiumConfiguration -> consortiumConfiguration
.map(configuration -> consortiumUserTenantsRetriever.getUserTenants(configuration.consortiumId(), requestContext)
.map(userTenants -> filterPiecesByUserTenants(pieces, userTenants)))
.orElse(Future.succeededFuture(pieces)));
}

private List<Piece> filterPiecesByUserTenants(List<Piece> pieces, List<String> userTenants) {
return pieces.stream()
.filter(piece -> Optional.ofNullable(piece.getReceivingTenantId())
.map(userTenants::contains)
.orElse(true))
.toList();
}

public Future<List<Piece>> getPiecesByIds(List<String> pieceIds, RequestContext requestContext) {
logger.debug("getPiecesByIds:: start to retrieving pieces by ids: {}", pieceIds);
var futures = ofSubLists(new ArrayList<>(pieceIds), MAX_IDS_FOR_GET_RQ_15)
.map(HelperUtils::convertIdsToCqlQuery)
.map(query -> getPieces(Integer.MAX_VALUE, 0, query, requestContext))
.map(query -> getAllPieces(query, requestContext))
.toList();
return collectResultsOnSuccess(futures)
.map(lists -> lists.stream()
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/folio/service/pieces/util/UserTenantFields.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.folio.service.pieces.util;

public enum UserTenantFields {

USER_ID("userId"),
TENANT_ID("tenantId"),
COLLECTION_USER_TENANTS("userTenants");

private final String value;

UserTenantFields(String value) {
this.value = value;
}

public String getValue() {
return value;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.core.models.RequestEntry;
import org.folio.rest.jaxrs.model.PieceCollection;
import org.folio.service.consortium.ConsortiumConfigurationService;
import org.folio.service.consortium.ConsortiumUserTenantsRetriever;
import org.folio.service.pieces.PieceStorageService;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -235,15 +237,27 @@ public RestClient restClient() {
}

@Bean
public PieceStorageService pieceStorageService(RestClient restClient) {
return spy(new PieceStorageService(restClient));
public PieceStorageService pieceStorageService(ConsortiumConfigurationService consortiumConfigurationService,
ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever,
RestClient restClient) {
return spy(new PieceStorageService(consortiumConfigurationService, consortiumUserTenantsRetriever, restClient));
}

@Bean
public CirculationRequestsRetriever circulationRequestsRetriever(PieceStorageService pieceStorageService, RestClient restClient) {
return new CirculationRequestsRetriever(pieceStorageService, restClient);
}

@Bean
ConsortiumConfigurationService consortiumConfigurationService(RestClient restClient) {
return new ConsortiumConfigurationService(restClient);
}

@Bean
ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever(RestClient restClient) {
return new ConsortiumUserTenantsRetriever(restClient);
}

}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void testGetHoldingSummaryById() throws IOException {
when(purchaseOrderLineService.getOrderLines(anyString(), anyInt(), anyInt(), any()))
.thenReturn(Future.succeededFuture(polines));

when(pieceStorageService.getPieces(anyInt(), anyInt(), anyString(), any()))
when(pieceStorageService.getAllPieces(anyString(), any()))
.thenReturn(Future.succeededFuture(pieces));

var hs = holdingsSummaryService.getHoldingsSummary(UUID.randomUUID().toString(), requestContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.folio.service.caches.InventoryCache;
import org.folio.service.configuration.ConfigurationEntriesService;
import org.folio.service.consortium.ConsortiumConfigurationService;
import org.folio.service.consortium.ConsortiumUserTenantsRetriever;
import org.folio.service.consortium.SharingInstanceService;
import org.folio.service.inventory.InventoryHoldingManager;
import org.folio.service.inventory.InventoryItemManager;
Expand Down Expand Up @@ -221,19 +222,30 @@ static class ContextConfiguration {
return new ProtectionService(acquisitionsUnitsService);
}

@Bean PieceStorageService pieceStorageService(RestClient restClient) {
return new PieceStorageService(restClient);
@Bean PieceStorageService pieceStorageService(ConsortiumConfigurationService consortiumConfigurationService,
ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever,
RestClient restClient) {
return new PieceStorageService(consortiumConfigurationService, consortiumUserTenantsRetriever, restClient);
}

@Bean InventoryService inventoryService (RestClient restClient) {
return new InventoryService(restClient);
}

@Bean SharingInstanceService sharingInstanceService (RestClient restClient) {
return new SharingInstanceService(restClient);
}
@Bean ConsortiumConfigurationService consortiumConfigurationService (RestClient restClient) {

@Bean
ConsortiumConfigurationService consortiumConfigurationService(RestClient restClient) {
return new ConsortiumConfigurationService(restClient);
}

@Bean
ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever(RestClient restClient) {
return new ConsortiumUserTenantsRetriever(restClient);
}

@Bean PurchaseOrderStorageService purchaseOrderStorageService () {
return mock(PurchaseOrderStorageService.class);
}
Expand Down
Loading
Loading