diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index d08f8d27c..639f2e6bb 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -98,12 +98,8 @@ "orders.item.delete" ], "modulePermissions": [ + "finance.transactions.batch", "finance.transactions.collection.get", - "finance.encumbrances.item.delete", - "finance.encumbrances.item.post", - "finance.encumbrances.item.put", - "finance.release-encumbrance.item.post", - "finance.order-transaction-summaries.item.put", "orders-storage.purchase-orders.item.get", "orders-storage.purchase-orders.item.delete", "orders-storage.po-lines.collection.get", @@ -220,22 +216,14 @@ "orders-storage.pieces.item.post", "orders-storage.po-lines.collection.get", "finance.funds.collection.get", - "finance.transactions.collection.get", "finance.budgets.collection.get", "finance.funds.budget.item.get", - "finance.encumbrances.item.delete", - "finance.encumbrances.item.post", - "finance.encumbrances.item.put", "finance.pending-payments.item.put", "finance.ledgers.current-fiscal-year.item.get", "finance.fiscal-years.item.get", - "finance-storage.order-transaction-summaries.item.get", - "finance.order-transaction-summaries.item.post", - "finance.order-transaction-summaries.item.put", - "finance.invoice-transaction-summaries.item.put", - "finance.release-encumbrance.item.post", "finance.expense-classes.collection.get", - "finance-storage.transactions.item.put", + "finance.transactions.batch", + "finance.transactions.collection.get", "finance-storage.ledgers.collection.get", "finance-storage.budget-expense-classes.collection.get", "inventory.instances.collection.get", @@ -277,12 +265,8 @@ "orders.po-lines.item.delete" ], "modulePermissions": [ + "finance.transactions.batch", "finance.transactions.collection.get", - "finance.encumbrances.item.post", - "finance.release-encumbrance.item.post", - "finance.encumbrances.item.put", - "finance.order-transaction-summaries.item.put", - "finance.encumbrances.item.delete", "orders-storage.purchase-orders.item.get", "orders-storage.po-lines.item.get", "orders-storage.po-lines.item.delete", @@ -391,8 +375,7 @@ "acquisitions-units-storage.units.collection.get", "acquisitions-units-storage.memberships.collection.get", "orders-storage.purchase-orders.collection.get", - "finance.encumbrances.item.put", - "finance.order-transaction-summaries.item.put", + "finance.transactions.batch", "finance.transactions.collection.get" ] }, @@ -419,8 +402,7 @@ "inventory-storage.holdings.item.get", "inventory-storage.items.item.post", "inventory-storage.loan-types.collection.get", - "finance.encumbrances.item.put", - "finance.order-transaction-summaries.item.put", + "finance.transactions.batch", "finance.transactions.collection.get", "orders-storage.pieces.collection.get", "orders-storage.pieces.item.put", @@ -503,10 +485,7 @@ "inventory-storage.instance-statuses.collection.get", "finance.funds.budget.item.get", "finance.fiscal-years.item.get", - "finance.order-transaction-summaries.item.get", - "finance.order-transaction-summaries.item.post", - "finance.order-transaction-summaries.item.put", - "finance.encumbrances.item.put", + "finance.transactions.batch", "finance-storage.ledgers.collection.get", "orders-storage.pieces.item.post", "orders-storage.pieces.collection.get", @@ -553,10 +532,7 @@ "inventory-storage.holdings-sources.collection.get", "inventory-storage.items.item.post", "inventory-storage.instance-statuses.collection.get", - "finance.order-transaction-summaries.item.get", - "finance.order-transaction-summaries.item.post", - "finance.order-transaction-summaries.item.put", - "finance.encumbrances.item.put", + "finance.transactions.batch", "finance-storage.ledgers.collection.get", "orders-storage.pieces.item.get", "orders-storage.pieces.item.post", @@ -587,18 +563,12 @@ "inventory.items.collection.get", "inventory-storage.holdings.item.get", "inventory-storage.holdings.item.delete", - "finance.encumbrances.item.put", - "finance.encumbrances.item.post", - "finance.encumbrances.item.delete", - "finance.order-transaction-summaries.item.get", - "finance.order-transaction-summaries.item.post", - "finance.order-transaction-summaries.item.put", "finance.funds.collection.get", "finance.funds.budget.item.get", "finance.fiscal-years.item.get", + "finance.transactions.batch", "finance.transactions.collection.get", "finance-storage.ledgers.collection.get", - "finance-storage.order-transaction-summaries.item.get", "orders-storage.pieces.item.delete", "orders-storage.pieces.item.get", "orders-storage.pieces.collection.get", @@ -961,8 +931,8 @@ "modulePermissions": [ "configuration.entries.collection.get", "finance-storage.funds.collection.get", - "finance.encumbrances.item.delete", "finance.exchange-rate.item.get", + "finance.transactions.batch", "finance.transactions.collection.get", "orders-storage.purchase-orders.collection.get", "orders-storage.po-lines.collection.get", @@ -1126,11 +1096,7 @@ }, { "id": "finance.transactions", - "version": "5.0" - }, - { - "id": "finance.order-transaction-summaries", - "version": "1.2" + "version": "5.1" }, { "id": "finance.ledgers", @@ -1164,10 +1130,6 @@ "id": "finance-storage.budget-expense-classes", "version": "2.0" }, - { - "id": "finance-storage.transactions", - "version": "4.0" - }, { "id": "finance.exchange-rate", "version": "1.0" @@ -1770,22 +1732,15 @@ "finance.funds.budget.item.get", "finance.funds.collection.get", "finance.budgets.collection.get", - "finance.encumbrances.item.delete", - "finance.encumbrances.item.post", - "finance.encumbrances.item.put", + "finance.transactions.batch", "finance.transactions.collection.get", "finance.transactions.item.get", "finance.ledgers.current-fiscal-year.item.get", "finance.fiscal-years.item.get", - "finance.order-transaction-summaries.item.post", - "finance.order-transaction-summaries.item.put", "finance-storage.ledgers.collection.get", - "finance-storage.order-transaction-summaries.item.get", "finance.exchange-rate.item.get", - "finance.release-encumbrance.item.post", "finance-storage.budget-expense-classes.collection.get", "finance.expense-classes.collection.get", - "finance-storage.transactions.item.put", "inventory.instances.collection.get", "inventory.instances.item.post", "inventory.items.collection.get", @@ -1841,23 +1796,17 @@ "orders-storage.alerts.item.get", "orders-storage.reporting-codes.item.get", "configuration.entries.collection.get", - "finance.encumbrances.item.post", - "finance.encumbrances.item.put", "finance.funds.budget.item.get", "finance.funds.collection.get", "finance.budgets.collection.get", "finance.fiscal-years.item.get", "finance.ledgers.current-fiscal-year.item.get", + "finance.transactions.batch", "finance.transactions.collection.get", "finance.transactions.item.get", "finance.exchange-rate.item.get", - "finance.order-transaction-summaries.item.post", - "finance.order-transaction-summaries.item.put", - "finance-storage.order-transaction-summaries.item.get", - "finance.release-encumbrance.item.post", "finance.expense-classes.collection.get", "finance-storage.budget-expense-classes.collection.get", - "finance-storage.transactions.item.put", "finance-storage.ledgers.collection.get", "inventory.instances.collection.get", "inventory.instances.item.post", diff --git a/src/main/java/org/folio/config/ApplicationConfig.java b/src/main/java/org/folio/config/ApplicationConfig.java index 1fbd7c03e..1bdbf1002 100644 --- a/src/main/java/org/folio/config/ApplicationConfig.java +++ b/src/main/java/org/folio/config/ApplicationConfig.java @@ -57,8 +57,6 @@ import org.folio.service.finance.transaction.PendingToPendingEncumbranceStrategy; import org.folio.service.finance.transaction.ReceivingEncumbranceStrategy; import org.folio.service.finance.transaction.TransactionService; -import org.folio.service.finance.transaction.summary.InvoiceTransactionSummariesService; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.folio.service.inventory.InventoryManager; import org.folio.service.inventory.InventoryService; import org.folio.service.invoice.InvoiceLineService; @@ -235,11 +233,10 @@ BudgetRestrictionService budgetRestrictionService() { @Bean EncumbranceService encumbranceService(TransactionService transactionService, - OrderTransactionSummariesService orderTransactionSummariesService, InvoiceLineService invoiceLineService, OrderInvoiceRelationService orderInvoiceRelationService, FiscalYearService fiscalYearService) { - return new EncumbranceService(transactionService, orderTransactionSummariesService, invoiceLineService, orderInvoiceRelationService, fiscalYearService); + return new EncumbranceService(transactionService, invoiceLineService, orderInvoiceRelationService, fiscalYearService); } @Bean @@ -271,22 +268,10 @@ TransactionService transactionService(RestClient restClient) { return new TransactionService(restClient); } - @Bean - OrderTransactionSummariesService transactionSummariesService(RestClient restClient) { - return new OrderTransactionSummariesService(restClient); - } - - @Bean - InvoiceTransactionSummariesService invoiceTransactionSummariesService(RestClient restClient) { - return new InvoiceTransactionSummariesService(restClient); - } - @Bean EncumbranceWorkflowStrategy openToPendingEncumbranceStrategy(EncumbranceService encumbranceService, - OrderTransactionSummariesService orderTransactionSummariesService, EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder) { - return new OpenToPendingEncumbranceStrategy(encumbranceService, orderTransactionSummariesService, - encumbranceRelationsHoldersBuilder); + return new OpenToPendingEncumbranceStrategy(encumbranceService, encumbranceRelationsHoldersBuilder); } @Bean @@ -326,10 +311,8 @@ EncumbranceWorkflowStrategy pendingToOpenEncumbranceStrategy(EncumbranceService @Bean EncumbranceWorkflowStrategy openToClosedEncumbranceStrategy(EncumbranceService encumbranceService, - EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder, - OrderTransactionSummariesService orderTransactionSummariesService) { - return new OpenToClosedEncumbranceStrategy(encumbranceService, encumbranceRelationsHoldersBuilder, - orderTransactionSummariesService); + EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder) { + return new OpenToClosedEncumbranceStrategy(encumbranceService, encumbranceRelationsHoldersBuilder); } @Bean @@ -372,11 +355,9 @@ OrderReEncumberService orderReEncumberService(PurchaseOrderStorageService purcha LedgerRolloverProgressService ledgerRolloverProgressService, PurchaseOrderLineService purchaseOrderLineService, TransactionService transactionService, - OrderTransactionSummariesService orderTransactionSummariesService, BudgetRestrictionService budgetRestrictionService) { return new OrderReEncumberService(purchaseOrderStorageService, reEncumbranceHoldersBuilder, ledgerRolloverErrorService, - ledgerRolloverProgressService, purchaseOrderLineService, transactionService, - orderTransactionSummariesService, budgetRestrictionService); + ledgerRolloverProgressService, purchaseOrderLineService, transactionService, budgetRestrictionService); } @Bean @@ -739,8 +720,11 @@ OrderTemplatesService orderTemplatesService() { return new PoLineInvoiceLineHolderBuilder(invoiceLineService); } - @Bean POLInvoiceLineRelationService polInvoiceLineRelationService(InvoiceLineService invoiceLineService, PendingPaymentService pendingPaymentService, InvoiceTransactionSummariesService invoiceTransactionSummariesService, PoLineInvoiceLineHolderBuilder poLineInvoiceLineHolderBuilder) { - return new POLInvoiceLineRelationService(invoiceLineService, pendingPaymentService, invoiceTransactionSummariesService, poLineInvoiceLineHolderBuilder); + @Bean POLInvoiceLineRelationService polInvoiceLineRelationService(InvoiceLineService invoiceLineService, + PendingPaymentService pendingPaymentService, PoLineInvoiceLineHolderBuilder poLineInvoiceLineHolderBuilder, + TransactionService transactionService) { + return new POLInvoiceLineRelationService(invoiceLineService, pendingPaymentService, poLineInvoiceLineHolderBuilder, + transactionService); } @Bean diff --git a/src/main/java/org/folio/helper/PurchaseOrderLineHelper.java b/src/main/java/org/folio/helper/PurchaseOrderLineHelper.java index d6fe18ae7..3fd16df80 100644 --- a/src/main/java/org/folio/helper/PurchaseOrderLineHelper.java +++ b/src/main/java/org/folio/helper/PurchaseOrderLineHelper.java @@ -314,16 +314,14 @@ public Future updateOrderLine(CompositePoLine compOrderLine, RequestContex private Future updateEncumbranceStatus(CompositePoLine compOrderLine, JsonObject lineFromStorage, RequestContext requestContext) { PoLine poLine = lineFromStorage.mapTo(PoLine.class); - if(isReleaseEncumbrances(compOrderLine, poLine)) { + if (isReleaseEncumbrances(compOrderLine, poLine)) { logger.info("Encumbrances releasing for poLineId={} where paymentStatus={}", compOrderLine.getId(), compOrderLine.getPaymentStatus()); return encumbranceService.getPoLineUnreleasedEncumbrances(compOrderLine.getId(), requestContext) - .compose(transactionList -> encumbranceService.updateOrderTransactionSummary(compOrderLine, transactionList, requestContext) - .compose(v -> encumbranceService.releaseEncumbrances(transactionList, requestContext))); + .compose(transactionList -> encumbranceService.releaseEncumbrances(transactionList, requestContext)); } else if (isUnreleasedEncumbrances(compOrderLine, poLine)) { logger.info("Encumbrances unreleasing for poLineId={} where paymentStatus={}", compOrderLine.getId(), compOrderLine.getPaymentStatus()); return encumbranceService.getPoLineReleasedEncumbrances(compOrderLine, requestContext) - .compose(transactionList -> encumbranceService.updateOrderTransactionSummary(compOrderLine, transactionList, requestContext) - .compose(v -> encumbranceService.unreleaseEncumbrances(transactionList, requestContext))); + .compose(transactionList -> encumbranceService.unreleaseEncumbrances(transactionList, requestContext)); } return Future.succeededFuture(); } diff --git a/src/main/java/org/folio/models/EncumbrancesProcessingHolder.java b/src/main/java/org/folio/models/EncumbrancesProcessingHolder.java index 6b3d7318a..25e1b92e1 100644 --- a/src/main/java/org/folio/models/EncumbrancesProcessingHolder.java +++ b/src/main/java/org/folio/models/EncumbrancesProcessingHolder.java @@ -5,10 +5,7 @@ import org.folio.rest.acq.model.finance.Transaction; -import com.google.common.collect.ImmutableList; - public class EncumbrancesProcessingHolder { - private List encumbrancesFromStorage; private List encumbrancesForRelease; private List encumbrancesForCreate; private List encumbrancesForDelete; @@ -18,7 +15,6 @@ public class EncumbrancesProcessingHolder { private List encumbrancesToReleaseAfter; public EncumbrancesProcessingHolder() { - this.encumbrancesFromStorage = new ArrayList<>(); this.encumbrancesForCreate = new ArrayList<>(); this.encumbrancesForDelete = new ArrayList<>(); this.encumbrancesForUpdate = new ArrayList<>(); @@ -63,11 +59,6 @@ public EncumbrancesProcessingHolder withEncumbrancesForRelease(List return this; } - public EncumbrancesProcessingHolder withEncumbrancesFromStorage(List encumbrancesFromStorage) { - this.encumbrancesFromStorage = new ArrayList<>(encumbrancesFromStorage); - return this; - } - public EncumbrancesProcessingHolder withEncumbrancesForUnrelease(List encumbrancesForUnrelease) { this.encumbrancesForUnrelease = new ArrayList<>(encumbrancesForUnrelease); return this; @@ -113,10 +104,7 @@ public List getEncumbrancesToUnreleaseAfter() { public int getAllEncumbrancesQuantity() { return encumbrancesForCreate.size() + encumbrancesForUpdate.size() - + encumbrancesForRelease.size() + encumbrancesForUnrelease.size(); - } - - public List getEncumbrancesFromStorage() { - return ImmutableList.copyOf(encumbrancesFromStorage); + + encumbrancesForRelease.size() + encumbrancesForUnrelease.size() + + encumbrancesForDelete.size(); } } diff --git a/src/main/java/org/folio/orders/utils/ResourcePathResolver.java b/src/main/java/org/folio/orders/utils/ResourcePathResolver.java index 1c29369fa..50b3da277 100644 --- a/src/main/java/org/folio/orders/utils/ResourcePathResolver.java +++ b/src/main/java/org/folio/orders/utils/ResourcePathResolver.java @@ -28,17 +28,15 @@ private ResourcePathResolver() { public static final String PAYMENT_STATUS = "paymentStatus"; public static final String ORDER_TEMPLATES = "orderTemplates"; public static final String TITLES = "titles"; - public static final String ENCUMBRANCES = "finance.encumbrances"; public static final String FUNDS = "finance.funds"; public static final String BUDGETS = "finance.budgets"; public static final String LEDGERS = "finance.ledgers"; - public static final String ORDER_TRANSACTION_SUMMARIES = "finance.order-summaries"; public static final String REASONS_FOR_CLOSURE = "configuration.reasons-for-closure"; public static final String PREFIXES = "configuration.prefixes"; public static final String SUFFIXES = "configuration.suffixes"; public static final String TRANSACTIONS_ENDPOINT = "finance.transactions"; public static final String USER_TENANTS_ENDPOINT = "user.tenants"; - public static final String FINANCE_RELEASE_ENCUMBRANCE = "finance.release-encumbrance"; + public static final String FINANCE_BATCH_TRANSACTIONS = "finance.batch-all-or-nothing"; public static final String BUDGET_EXPENSE_CLASSES = "finance-storage.budget-expense-classes"; public static final String CURRENT_BUDGET = "finance.current-budgets"; public static final String FINANCE_EXCHANGE_RATE = "finance/exchange-rate"; @@ -68,18 +66,16 @@ private ResourcePathResolver() { apis.put(RECEIVING_HISTORY, "/orders-storage/receiving-history"); apis.put(PO_LINE_NUMBER, "/orders-storage/po-line-number"); apis.put(ORDER_TEMPLATES, "/orders-storage/order-templates"); - apis.put(ENCUMBRANCES, "/finance/encumbrances"); apis.put(FUNDS, "/finance/funds"); apis.put(BUDGETS, "/finance/budgets"); apis.put(LEDGERS, "/finance-storage/ledgers"); - apis.put(ORDER_TRANSACTION_SUMMARIES, "/finance/order-transaction-summaries"); apis.put(TITLES, "/orders-storage/titles"); apis.put(REASONS_FOR_CLOSURE, "/orders-storage/configuration/reasons-for-closure"); apis.put(PREFIXES, "/orders-storage/configuration/prefixes"); apis.put(SUFFIXES, "/orders-storage/configuration/suffixes"); apis.put(TRANSACTIONS_ENDPOINT, "/finance/transactions"); apis.put(USER_TENANTS_ENDPOINT, "/user-tenants"); - apis.put(FINANCE_RELEASE_ENCUMBRANCE, "/finance/release-encumbrance"); + apis.put(FINANCE_BATCH_TRANSACTIONS, "/finance/transactions/batch-all-or-nothing"); apis.put(BUDGET_EXPENSE_CLASSES, "/finance-storage/budget-expense-classes"); apis.put(CURRENT_BUDGET, "/finance/funds/%s/budget"); apis.put(FINANCE_EXCHANGE_RATE, "/finance/exchange-rate"); diff --git a/src/main/java/org/folio/rest/core/RestClient.java b/src/main/java/org/folio/rest/core/RestClient.java index 8bbd9f446..17a787c98 100644 --- a/src/main/java/org/folio/rest/core/RestClient.java +++ b/src/main/java/org/folio/rest/core/RestClient.java @@ -69,6 +69,18 @@ public Future post(String endpoint, T entity, Class responseType, Requ .onFailure(log::error); } + public Future postEmptyResponse(String endpoint, T entity, RequestContext requestContext) { + log.debug(SENDING_POST_WITH_BODY_MSG, () -> endpoint, () -> JsonObject.mapFrom(entity).encodePrettily()); + var caseInsensitiveHeader = convertToCaseInsensitiveMap(requestContext.getHeaders()); + return getVertxWebClient(requestContext.getContext()) + .postAbs(buildAbsEndpoint(caseInsensitiveHeader, endpoint)) + .putHeaders(caseInsensitiveHeader) + .expect(SUCCESS_RESPONSE_PREDICATE) + .sendJson(entity) + .onFailure(log::error) + .mapEmpty(); + } + private MultiMap convertToCaseInsensitiveMap(Map okapiHeaders) { return MultiMap.caseInsensitiveMultiMap() .addAll(okapiHeaders) diff --git a/src/main/java/org/folio/service/finance/transaction/AbstractTransactionManagingService.java b/src/main/java/org/folio/service/finance/transaction/AbstractTransactionManagingService.java index 0d54e6896..c77a61ef6 100644 --- a/src/main/java/org/folio/service/finance/transaction/AbstractTransactionManagingService.java +++ b/src/main/java/org/folio/service/finance/transaction/AbstractTransactionManagingService.java @@ -1,16 +1,13 @@ package org.folio.service.finance.transaction; import io.vertx.core.Future; -import org.folio.okapi.common.GenericCompositeFuture; import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; -import org.folio.rest.core.models.RequestEntry; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import static one.util.streamex.StreamEx.ofSubLists; @@ -20,13 +17,6 @@ public abstract class AbstractTransactionManagingService { - private static final Map TRANSACTION_ENDPOINTS = Map.of( - Transaction.TransactionType.PAYMENT, "/finance/payments", - Transaction.TransactionType.CREDIT, "/finance/credits", - Transaction.TransactionType.PENDING_PAYMENT, "/finance/pending-payments", - Transaction.TransactionType.ENCUMBRANCE, "/finance/encumbrances" - ); - protected final TransactionService transactionService; protected final RestClient restClient; @@ -44,31 +34,11 @@ public Future> getTransactionsByEncumbranceIds(List tr .collect(Collectors.toList())); } - public Future updateTransactions(List transactions, RequestContext requestContext) { - return GenericCompositeFuture.join(transactions.stream() - .map(transaction -> updateTransaction(transaction, requestContext)) - .collect(Collectors.toList())) - .mapEmpty(); - } - - private Future updateTransaction(Transaction transaction, RequestContext requestContext) { - RequestEntry requestEntry = new RequestEntry(getByIdEndpoint(transaction)).withId(transaction.getId()); - return restClient.put(requestEntry, transaction, requestContext); - } - private Future> getTransactionsChunksByEncumbranceIds(List ids, RequestContext requestContext) { String query = convertIdsToCqlQuery(ids, getEncumbranceIdentifierQuery()) ; return transactionService.getTransactions(query, requestContext); } - private String getEndpoint(Transaction transaction) { - return TRANSACTION_ENDPOINTS.get(transaction.getTransactionType()); - } - - private String getByIdEndpoint(Transaction transaction) { - return getEndpoint(transaction) + "/{id}"; - } - protected abstract String getEncumbranceIdentifierQuery(); } diff --git a/src/main/java/org/folio/service/finance/transaction/ClosedToOpenEncumbranceStrategy.java b/src/main/java/org/folio/service/finance/transaction/ClosedToOpenEncumbranceStrategy.java index 50ae436c3..252de2a64 100644 --- a/src/main/java/org/folio/service/finance/transaction/ClosedToOpenEncumbranceStrategy.java +++ b/src/main/java/org/folio/service/finance/transaction/ClosedToOpenEncumbranceStrategy.java @@ -82,7 +82,6 @@ public Future processEncumbrances(CompositePurchaseOrder compPO, Composite .filter(h -> h.getOldEncumbrance() == null) .collect(toList()); holder.withEncumbrancesForCreate(toBeCreatedHolders); - holder.withEncumbrancesFromStorage(transactions); holder.withEncumbrancesForUnrelease(transactions); return encumbranceService.createOrUpdateEncumbrances(holder, requestContext); }); diff --git a/src/main/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilder.java b/src/main/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilder.java index 096ca16af..0afd3ce9f 100644 --- a/src/main/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilder.java +++ b/src/main/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilder.java @@ -18,11 +18,13 @@ import javax.money.convert.CurrencyConversion; import javax.money.convert.ExchangeRateProvider; +import io.vertx.core.json.JsonObject; import org.folio.models.EncumbranceRelationsHolder; import org.folio.rest.acq.model.finance.Budget; import org.folio.rest.acq.model.finance.Encumbrance; import org.folio.rest.acq.model.finance.Fund; import org.folio.rest.acq.model.finance.Ledger; +import org.folio.rest.acq.model.finance.Metadata; import org.folio.rest.acq.model.finance.Tags; import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.core.exceptions.HttpException; @@ -291,6 +293,7 @@ private void mapHoldersToTransactions(List encumbran Transaction newTransaction = holder.getNewEncumbrance(); newTransaction.setId(existingTransaction.getId()); newTransaction.setVersion(existingTransaction.getVersion()); + newTransaction.setMetadata(JsonObject.mapFrom(existingTransaction.getMetadata()).mapTo(Metadata.class)); newTransaction.getEncumbrance() .withAmountExpended(existingTransaction.getEncumbrance().getAmountExpended()) .withAmountAwaitingPayment(existingTransaction.getEncumbrance().getAmountAwaitingPayment()); diff --git a/src/main/java/org/folio/service/finance/transaction/EncumbranceService.java b/src/main/java/org/folio/service/finance/transaction/EncumbranceService.java index ad59b3851..7e0f8923c 100644 --- a/src/main/java/org/folio/service/finance/transaction/EncumbranceService.java +++ b/src/main/java/org/folio/service/finance/transaction/EncumbranceService.java @@ -2,7 +2,6 @@ import static java.util.Objects.requireNonNullElse; import static java.util.stream.Collectors.toList; -import static org.folio.orders.utils.HelperUtils.calculateEstimatedPrice; import static org.folio.orders.utils.HelperUtils.collectResultsOnSuccess; import static org.folio.rest.core.exceptions.ErrorCodes.BUDGET_IS_INACTIVE; import static org.folio.rest.core.exceptions.ErrorCodes.BUDGET_NOT_FOUND_FOR_TRANSACTION; @@ -15,21 +14,18 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.UUID; import java.util.concurrent.CompletionException; -import javax.money.MonetaryAmount; - import org.apache.commons.collections4.CollectionUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.folio.HttpStatus; import org.folio.models.EncumbranceRelationsHolder; import org.folio.models.EncumbrancesProcessingHolder; -import org.folio.okapi.common.GenericCompositeFuture; import org.folio.rest.acq.model.finance.Encumbrance; -import org.folio.rest.acq.model.finance.Tags; import org.folio.rest.acq.model.finance.Transaction; +import org.folio.rest.acq.model.finance.TransactionPatch; import org.folio.rest.core.exceptions.ErrorCodes; import org.folio.rest.core.exceptions.HttpException; import org.folio.rest.core.models.RequestContext; @@ -40,13 +36,10 @@ import org.folio.rest.jaxrs.model.Parameter; import org.folio.rest.jaxrs.model.PoLine; import org.folio.service.finance.FiscalYearService; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.folio.service.invoice.InvoiceLineService; import org.folio.service.orders.OrderInvoiceRelationService; -import org.javamoney.moneta.function.MonetaryOperators; import io.vertx.core.Future; -import io.vertxconcurrent.Semaphore; public class EncumbranceService { @@ -57,19 +50,16 @@ public class EncumbranceService { private static final Logger logger = LogManager.getLogger(); private final TransactionService transactionService; - private final OrderTransactionSummariesService orderTransactionSummariesService; private final InvoiceLineService invoiceLineService; private final OrderInvoiceRelationService orderInvoiceRelationService; private final FiscalYearService fiscalYearService; public EncumbranceService(TransactionService transactionService, - OrderTransactionSummariesService orderTransactionSummariesService, InvoiceLineService invoiceLineService, OrderInvoiceRelationService orderInvoiceRelationService, FiscalYearService fiscalYearService) { this.transactionService = transactionService; - this.orderTransactionSummariesService = orderTransactionSummariesService; this.invoiceLineService = invoiceLineService; this.orderInvoiceRelationService = orderInvoiceRelationService; this.fiscalYearService = fiscalYearService; @@ -77,73 +67,102 @@ public EncumbranceService(TransactionService transactionService, public Future createOrUpdateEncumbrances(EncumbrancesProcessingHolder holder, RequestContext requestContext) { - if (holder.getAllEncumbrancesQuantity() == 0) return Future.succeededFuture(); return unreleaseEncumbrancesFirst(holder, requestContext) - .compose(v -> orderTransactionSummariesService.createOrUpdateOrderTransactionSummary(holder, requestContext)) - .compose(v -> createEncumbrances(holder.getEncumbrancesForCreate(), requestContext)) - .compose(v -> releaseEncumbrances(holder.getEncumbrancesForRelease(), requestContext)) - .compose(v -> unreleaseEncumbrances(holder.getEncumbrancesForUnrelease(), requestContext)) - .compose(v -> updateEncumbrances(holder, requestContext)) - .compose(v -> deleteEncumbrances(holder.getEncumbrancesForDelete(), requestContext)) - .compose(v -> releaseEncumbrancesAfter(holder, requestContext)); - } - - public Future createEncumbrances(List relationsHolders, RequestContext requestContext) { - if (CollectionUtils.isEmpty(relationsHolders)) - return Future.succeededFuture(); - - Semaphore semaphore = new Semaphore(1, requestContext.getContext().owner()); - - return requestContext.getContext().owner() - .>>executeBlocking(promise -> { - List> futures = new ArrayList<>(); - for (EncumbranceRelationsHolder holder : relationsHolders) { - semaphore.acquire(() -> { - Future createTransactionFuture = transactionService.createTransaction(holder.getNewEncumbrance(), requestContext) - .map(transaction -> { - holder.getFundDistribution().setEncumbrance(transaction.getId()); - return null; - }); - var future = createTransactionFuture.otherwise(fail -> { - checkCustomTransactionError(fail); - return null; - }) - .onComplete(asyncResult -> semaphore.release()); - - futures.add(future); - if (futures.size() == relationsHolders.size()) { - promise.complete(futures); - } - }); - + .compose(v -> batchProcess(holder, requestContext)) + .compose(v -> releaseEncumbrancesAfter(holder, requestContext)); + } + + public Future batchProcess(EncumbrancesProcessingHolder holder, RequestContext requestContext) { + List transactionsToCreate = prepareTransactionsToCreate(holder.getEncumbrancesForCreate()); + List transactionsToUpdate = prepareTransactionsToUpdate(holder); + List transactionsToDelete = prepareTransactionsToDelete(holder.getEncumbrancesForDelete()); + List idsOfTransactionsToDelete = transactionsToDelete.stream().map(Transaction::getId).toList(); + List transactionPatches = Collections.emptyList(); + return transactionService.batchAllOrNothing(transactionsToCreate, transactionsToUpdate, idsOfTransactionsToDelete, + transactionPatches, requestContext) + .recover(t -> { + try { + checkCustomTransactionError(t); + } catch(Exception ex) { + return Future.failedFuture(ex); } + return Future.failedFuture(t); }) - .compose(futures -> GenericCompositeFuture.all(new ArrayList<>(futures)) - .mapEmpty()); + .compose(v -> { + if (transactionsToDelete.isEmpty()) { + return Future.succeededFuture(); + } + return deleteEncumbranceLinksInInvoiceLines(transactionsToDelete, requestContext); + }); } + private List prepareTransactionsToCreate(List relationsHolders) { + if (CollectionUtils.isEmpty(relationsHolders)) { + return Collections.emptyList(); + } + relationsHolders.forEach(holder -> { + Transaction encumbrance = holder.getNewEncumbrance(); + if (encumbrance.getId() == null) { + encumbrance.setId(UUID.randomUUID().toString()); + } + holder.getFundDistribution().setEncumbrance(encumbrance.getId()); + }); + return relationsHolders.stream().map(EncumbranceRelationsHolder::getNewEncumbrance).toList(); + } + + private List prepareTransactionsToUpdate(EncumbrancesProcessingHolder holder) { + ArrayList encumbrances = new ArrayList<>( + holder.getEncumbrancesForUpdate().stream() + .map(EncumbranceRelationsHolder::getNewEncumbrance) + .toList()); + holder.getEncumbrancesForRelease().forEach(encToRelease -> { + if (encumbrances.stream().noneMatch(enc -> enc.getId().equals(encToRelease.getId()))) { + encToRelease.getEncumbrance().setStatus(Encumbrance.Status.RELEASED); + encumbrances.add(encToRelease); + } else { + encumbrances.stream() + .filter(enc -> enc.getId().equals(encToRelease.getId())) + .forEach(enc -> enc.getEncumbrance().setStatus(Encumbrance.Status.RELEASED)); + } + }); + holder.getEncumbrancesForUnrelease().forEach(encToUnrelease -> { + if (encumbrances.stream().noneMatch(enc -> enc.getId().equals(encToUnrelease.getId()))) { + encToUnrelease.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED); + encumbrances.add(encToUnrelease); + } else { + encumbrances.stream() + .filter(enc -> enc.getId().equals(encToUnrelease.getId())) + .forEach(enc -> enc.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED)); + } + }); + return encumbrances; + } + + private List prepareTransactionsToDelete(List holders) { + // before deleting encumbrances, set the fund distribution encumbrance to null if a new encumbrance has not been created + // (as with pending->pending) + holders.stream() + .filter(erh -> erh.getFundDistribution() != null && erh.getOldEncumbrance().getId().equals(erh.getFundDistribution().getEncumbrance())) + .forEach(erh -> erh.getFundDistribution().setEncumbrance(null)); + return holders.stream() + .map(EncumbranceRelationsHolder::getOldEncumbrance) + .toList(); + } public Future updateEncumbrancesOrderStatusAndReleaseIfClosed(CompositePurchaseOrder compPo, RequestContext requestContext) { logger.info("updateEncumbrancesOrderStatusAndReleaseIfClosed:: orderId {} ", compPo.getId()); return getOrderUnreleasedEncumbrances(compPo.getId(), requestContext).compose(encumbrs -> { if (isEncumbrancesOrderStatusUpdateNeeded(compPo.getWorkflowStatus(), encumbrs)) { - return orderTransactionSummariesService.updateTransactionSummary(compPo.getId(), encumbrs.size(), requestContext) - .map(v -> { - syncEncumbrancesOrderStatusAndReleaseIfClosed(compPo.getWorkflowStatus(), encumbrs); - return encumbrs; - }) - .compose(transactions -> transactionService.updateTransactions(transactions, requestContext)); + syncEncumbrancesOrderStatusAndReleaseIfClosed(compPo.getWorkflowStatus(), encumbrs); + // NOTE: we will have to use transactionPatches when it is available (see MODORDERS-1008) + return transactionService.batchUpdate(encumbrs, requestContext); } return Future.succeededFuture(); }); } - public Future updateOrderTransactionSummary(CompositePoLine compOrderLine, List encumbrs, RequestContext requestContext) { - return orderTransactionSummariesService.updateTransactionSummary(compOrderLine.getPurchaseOrderId(), encumbrs.size(), requestContext); - } - private void syncEncumbrancesOrderStatusAndReleaseIfClosed(CompositePurchaseOrder.WorkflowStatus workflowStatus, List encumbrances) { Encumbrance.OrderStatus orderStatus = Encumbrance.OrderStatus.fromValue(workflowStatus.value()); @@ -160,16 +179,6 @@ private boolean isEncumbrancesOrderStatusUpdateNeeded(CompositePurchaseOrder.Wor } - private Future updateEncumbrances(EncumbrancesProcessingHolder holder, RequestContext requestContext) { - if (holder.getEncumbrancesForUpdate().isEmpty()) - return Future.succeededFuture(); - - List encumbrances = holder.getEncumbrancesForUpdate().stream() - .map(EncumbranceRelationsHolder::getNewEncumbrance) - .collect(toList()); - return updateEncumbrances(encumbrances, requestContext); - } - public Future> getOrderEncumbrances(String orderId, RequestContext requestContext) { return transactionService.getTransactions(buildEncumbrancesByOrderQuery(orderId), requestContext); } @@ -229,80 +238,45 @@ public Future> getEncumbrancesByPoLinesFromCurrentFy(Map encumbrances.stream().flatMap(Collection::stream).collect(toList())); } - public void updateEncumbrance(FundDistribution fundDistribution, CompositePoLine poLine, Transaction trEncumbrance) { - MonetaryAmount estimatedPrice = calculateEstimatedPrice(poLine.getCost()); - trEncumbrance.setAmount(calculateAmountEncumbered(fundDistribution, estimatedPrice)); - trEncumbrance.setExpenseClassId(fundDistribution.getExpenseClassId()); - if (Objects.nonNull(poLine.getTags())) { - trEncumbrance.setTags(new Tags().withTagList(poLine.getTags().getTagList())); - } - Encumbrance encumbrance = trEncumbrance.getEncumbrance(); - encumbrance.setStatus(Encumbrance.Status.UNRELEASED); - encumbrance.setInitialAmountEncumbered(trEncumbrance.getAmount()); - } - public Future releaseEncumbrances(List encumbrances, RequestContext requestContext) { - if (encumbrances.isEmpty()) + if (encumbrances.isEmpty()) { return Future.succeededFuture(); - - encumbrances.forEach(transaction -> transaction.getEncumbrance().setStatus(Encumbrance.Status.RELEASED)); - return transactionService.updateTransactions(encumbrances, requestContext); + } + return transactionService.batchRelease(encumbrances, requestContext); } public Future unreleaseEncumbrances(List encumbrances, RequestContext requestContext) { - if (encumbrances.isEmpty()) + if (encumbrances.isEmpty()) { return Future.succeededFuture(); - - encumbrances.forEach(transaction -> transaction.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED)); - return transactionService.updateTransactions(encumbrances, requestContext); - } - - public Future updateEncumbrances(List transactions, RequestContext requestContext) { - return transactionService.updateTransactions(transactions, requestContext); + } + return transactionService.batchUnrelease(encumbrances, requestContext); } - public Future deleteEncumbrances(List holders, RequestContext requestContext) { - if (holders.isEmpty()) + public Future updateEncumbrances(List encumbrances, RequestContext requestContext) { + if (encumbrances.isEmpty()) { return Future.succeededFuture(); - - // before deleting encumbrances, set the fund distribution encumbrance to null if a new encumbrance has not been created - // (as with pending->pending) - holders.stream() - .filter(erh -> erh.getFundDistribution() != null && erh.getOldEncumbrance().getId().equals(erh.getFundDistribution().getEncumbrance())) - .forEach(erh -> erh.getFundDistribution().setEncumbrance(null)); - List transactions = holders.stream() - .map(EncumbranceRelationsHolder::getOldEncumbrance) - .collect(toList()); - if (transactions.isEmpty()) { - return Future.succeededFuture(); - } else { - return transactionService.deleteTransactions(transactions, requestContext) - .compose(v -> deleteEncumbranceLinksInInvoiceLines(transactions, requestContext)); } + return transactionService.batchUpdate(encumbrances, requestContext); } public Future deletePoLineEncumbrances(PoLine poline, RequestContext requestContext) { return getPoLineEncumbrances(poline.getId(), requestContext) - .compose(encumbrances -> orderTransactionSummariesService.updateTransactionSummary(poline.getPurchaseOrderId(), encumbrances.size(), requestContext) - .compose(v -> releaseEncumbrances(encumbrances, requestContext)) - .compose(ok -> transactionService.deleteTransactions(encumbrances, requestContext))); + .compose(encumbrances -> { + if (encumbrances.isEmpty()) { + return Future.succeededFuture(); + } + return transactionService.batchReleaseAndDelete(encumbrances, requestContext); + }); } public Future deleteOrderEncumbrances(String orderId, RequestContext requestContext) { return getOrderEncumbrances(orderId, requestContext) - .compose(encumbrances -> orderTransactionSummariesService.updateTransactionSummary(orderId, encumbrances.size(), requestContext) - .compose(v -> releaseEncumbrances(encumbrances, requestContext)) - .compose(v -> transactionService.deleteTransactions(encumbrances, requestContext))); - } - - public static double calculateAmountEncumbered(FundDistribution distribution, MonetaryAmount estimatedPrice) { - if (distribution.getDistributionType() == FundDistribution.DistributionType.PERCENTAGE) { - return estimatedPrice.with(MonetaryOperators.percent(distribution.getValue())) - .with(MonetaryOperators.rounding()) - .getNumber() - .doubleValue(); - } - return distribution.getValue(); + .compose(encumbrances -> { + if (encumbrances.isEmpty()) { + return Future.succeededFuture(); + } + return transactionService.batchReleaseAndDelete(encumbrances, requestContext); + }); } public Future deleteEncumbranceLinksInInvoiceLines(List transactions, RequestContext requestContext) { @@ -415,10 +389,8 @@ private Future unreleaseEncumbrancesFirst(EncumbrancesProcessingHolder hol List encumbrances = holder.getEncumbrancesToUnreleaseBefore(); if (encumbrances.isEmpty()) return Future.succeededFuture(); - String orderId = encumbrances.get(0).getEncumbrance().getSourcePurchaseOrderId(); List encumbranceIds = encumbrances.stream().map(Transaction::getId).collect(toList()); - return orderTransactionSummariesService.updateOrCreateTransactionSummary(orderId, encumbrances.size(), requestContext) - .compose(v -> unreleaseEncumbrances(encumbrances, requestContext)) + return unreleaseEncumbrances(encumbrances, requestContext) .compose(v -> transactionService.getTransactionsByIds(encumbranceIds, requestContext)) .map(newEncumbrances -> { holder.getEncumbrancesForUpdate().forEach(h -> { @@ -436,16 +408,12 @@ private Future unreleaseEncumbrancesFirst(EncumbrancesProcessingHolder hol private Future releaseEncumbrancesAfter(EncumbrancesProcessingHolder holder, RequestContext requestContext) { // Get the updated version of the encumbrances before releasing them. + // NOTE: this could be done within batchProcess using patches (assuming patches are done after create/update; see MODORDERS-1008) List encumbrances = holder.getEncumbrancesToUnreleaseAfter(); if (encumbrances.isEmpty()) return Future.succeededFuture(); - String orderId = encumbrances.get(0).getEncumbrance().getSourcePurchaseOrderId(); List encumbranceIds = encumbrances.stream().map(Transaction::getId).collect(toList()); return transactionService.getTransactionsByIds(encumbranceIds, requestContext) - .compose(updatedEncumbrances -> - orderTransactionSummariesService.updateOrCreateTransactionSummary(orderId, updatedEncumbrances.size(), - requestContext) - .compose(v -> releaseEncumbrances(updatedEncumbrances, requestContext)) - ); + .compose(updatedEncumbrances -> releaseEncumbrances(updatedEncumbrances, requestContext)); } } diff --git a/src/main/java/org/folio/service/finance/transaction/EncumbrancesProcessingHolderBuilder.java b/src/main/java/org/folio/service/finance/transaction/EncumbrancesProcessingHolderBuilder.java index b2aba8b78..f57f728da 100644 --- a/src/main/java/org/folio/service/finance/transaction/EncumbrancesProcessingHolderBuilder.java +++ b/src/main/java/org/folio/service/finance/transaction/EncumbrancesProcessingHolderBuilder.java @@ -23,10 +23,6 @@ protected EncumbrancesProcessingHolder distributeHoldersByOperation( // also release transaction before delete List toRelease = toDelete.stream().map(EncumbranceRelationsHolder::getOldEncumbrance).collect(toList()); holder.withEncumbrancesForRelease(toRelease); - holder.withEncumbrancesFromStorage(encumbranceRelationsHolders.stream() - .map(EncumbranceRelationsHolder::getOldEncumbrance) - .filter(Objects::nonNull) - .collect(toList())); updateHolderToUpdateReleasedEncumbrances(holder); return holder; } diff --git a/src/main/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategy.java b/src/main/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategy.java index 05b59a833..4640e8695 100644 --- a/src/main/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategy.java +++ b/src/main/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategy.java @@ -6,7 +6,6 @@ import org.folio.rest.acq.model.finance.Encumbrance; import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.CompositePurchaseOrder; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.folio.service.orders.OrderWorkflowType; import io.vertx.core.Future; @@ -15,14 +14,11 @@ public class OpenToClosedEncumbranceStrategy implements EncumbranceWorkflowStrat private final EncumbranceService encumbranceService; private final EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder; - private final OrderTransactionSummariesService orderTransactionSummariesService; public OpenToClosedEncumbranceStrategy(EncumbranceService encumbranceService, - EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder, - OrderTransactionSummariesService orderTransactionSummariesService) { + EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder) { this.encumbranceService = encumbranceService; this.encumbranceRelationsHoldersBuilder = encumbranceRelationsHoldersBuilder; - this.orderTransactionSummariesService = orderTransactionSummariesService; } @Override @@ -40,8 +36,7 @@ public Future processEncumbrances(CompositePurchaseOrder compPO, Composite tr.getEncumbrance().setOrderStatus(CLOSED); tr.getEncumbrance().setStatus(Encumbrance.Status.RELEASED); }); - return orderTransactionSummariesService.updateTransactionSummary(compPO.getId(), transactions.size(), requestContext) - .compose(v -> encumbranceService.updateEncumbrances(transactions, requestContext)); + return encumbranceService.updateEncumbrances(transactions, requestContext); } }); } diff --git a/src/main/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategy.java b/src/main/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategy.java index d47b70e7b..95462c5d2 100644 --- a/src/main/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategy.java +++ b/src/main/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategy.java @@ -6,7 +6,6 @@ import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.CompositePurchaseOrder; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.folio.service.orders.OrderWorkflowType; import io.vertx.core.Future; @@ -14,14 +13,11 @@ public class OpenToPendingEncumbranceStrategy implements EncumbranceWorkflowStrategy { private final EncumbranceService encumbranceService; - private final OrderTransactionSummariesService orderTransactionSummariesService; private final EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder; public OpenToPendingEncumbranceStrategy(EncumbranceService encumbranceService, - OrderTransactionSummariesService orderTransactionSummariesService, EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder) { this.encumbranceService = encumbranceService; - this.orderTransactionSummariesService = orderTransactionSummariesService; this.encumbranceRelationsHoldersBuilder = encumbranceRelationsHoldersBuilder; } @@ -30,10 +26,8 @@ public Future processEncumbrances(CompositePurchaseOrder compPO, Composite RequestContext requestContext) { return getOrderEncumbrances(compPO, poAndLinesFromStorage, requestContext) - .map(this::makeEncumbrancesPending) - .compose(transactions -> orderTransactionSummariesService.updateTransactionSummary(compPO.getId(), transactions.size(), requestContext) - .map(vVoid -> transactions)) - .compose(transactions -> encumbranceService.updateEncumbrances(transactions, requestContext)); + .map(this::makeEncumbrancesPending) + .compose(transactions -> encumbranceService.updateEncumbrances(transactions, requestContext)); } private List makeEncumbrancesPending(List encumbrances) { diff --git a/src/main/java/org/folio/service/finance/transaction/PendingToPendingEncumbranceStrategy.java b/src/main/java/org/folio/service/finance/transaction/PendingToPendingEncumbranceStrategy.java index 11a28b8b8..2561fd62e 100644 --- a/src/main/java/org/folio/service/finance/transaction/PendingToPendingEncumbranceStrategy.java +++ b/src/main/java/org/folio/service/finance/transaction/PendingToPendingEncumbranceStrategy.java @@ -44,10 +44,6 @@ public OrderWorkflowType getStrategyName() { private EncumbrancesProcessingHolder distributeHoldersByOperation(List encumbranceRelationsHolders) { EncumbrancesProcessingHolder holder = new EncumbrancesProcessingHolder(); - holder.withEncumbrancesFromStorage(encumbranceRelationsHolders.stream() - .map(EncumbranceRelationsHolder::getOldEncumbrance) - .filter(Objects::nonNull) - .collect(toList())); List toDelete = getTransactionsToDelete(encumbranceRelationsHolders); List toRelease = toDelete.stream().map(EncumbranceRelationsHolder::getOldEncumbrance).collect(toList()); holder.withEncumbrancesForRelease(toRelease); diff --git a/src/main/java/org/folio/service/finance/transaction/TransactionService.java b/src/main/java/org/folio/service/finance/transaction/TransactionService.java index 2685018bc..aee7bf24f 100644 --- a/src/main/java/org/folio/service/finance/transaction/TransactionService.java +++ b/src/main/java/org/folio/service/finance/transaction/TransactionService.java @@ -3,6 +3,8 @@ import static one.util.streamex.StreamEx.ofSubLists; import static org.folio.orders.utils.HelperUtils.collectResultsOnSuccess; import static org.folio.orders.utils.HelperUtils.convertIdsToCqlQuery; +import static org.folio.orders.utils.ResourcePathResolver.FINANCE_BATCH_TRANSACTIONS; +import static org.folio.orders.utils.ResourcePathResolver.resourcesPath; import static org.folio.rest.RestConstants.MAX_IDS_FOR_GET_RQ_15; import static org.folio.rest.core.exceptions.ErrorCodes.ERROR_RETRIEVING_TRANSACTION; @@ -11,11 +13,17 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; -import org.folio.okapi.common.GenericCompositeFuture; +import io.vertx.core.json.JsonObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.folio.rest.acq.model.finance.Batch; +import org.folio.rest.acq.model.finance.Encumbrance; import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.acq.model.finance.TransactionCollection; +import org.folio.rest.acq.model.finance.TransactionPatch; import org.folio.rest.core.RestClient; import org.folio.rest.core.exceptions.HttpException; import org.folio.rest.core.models.RequestContext; @@ -26,9 +34,8 @@ import one.util.streamex.StreamEx; public class TransactionService { + private static final Logger log = LogManager.getLogger(); private static final String ENDPOINT = "/finance/transactions"; - private static final String ENCUMBRANCE_ENDPOINT = "/finance/encumbrances"; - private static final String ENCUMBRANCE_BY_ID_ENDPOINT = "/finance/encumbrances/{id}"; private final RestClient restClient; @@ -80,33 +87,60 @@ private Future> getTransactionsChunksByIds(Collection return getTransactions(query, requestContext); } - public Future createTransaction(Transaction transaction, RequestContext requestContext) { - RequestEntry requestEntry = new RequestEntry(ENCUMBRANCE_ENDPOINT); - return restClient.post(requestEntry, transaction, Transaction.class, requestContext); + public Future batchAllOrNothing(List transactionsToCreate, List transactionsToUpdate, + List idsOfTransactionsToDelete, List transactionPatches, RequestContext requestContext) { + Batch batch = new Batch(); + if (transactionsToCreate != null) { + transactionsToCreate.forEach(tr -> { + if (tr.getId() == null) { + tr.setId(UUID.randomUUID().toString()); + } + }); + batch.setTransactionsToCreate(transactionsToCreate); + } + if (transactionsToUpdate != null) { + batch.setTransactionsToUpdate(transactionsToUpdate); + } + if (idsOfTransactionsToDelete != null) { + batch.setIdsOfTransactionsToDelete(idsOfTransactionsToDelete); + } + if (transactionPatches != null) { + batch.setTransactionPatches(transactionPatches); + } + return restClient.postEmptyResponse(resourcesPath(FINANCE_BATCH_TRANSACTIONS), batch, requestContext) + .onSuccess(v -> log.info("batchAllOrNothing completed successfully")) + .onFailure(t -> log.error("batchAllOrNothing failed, batch={}", JsonObject.mapFrom(batch), t)); + } + + public Future batchCreate(List transactions, RequestContext requestContext) { + return batchAllOrNothing(transactions, null, null, null, requestContext); } - public Future updateTransaction(Transaction transaction, RequestContext requestContext) { - RequestEntry requestEntry = new RequestEntry(ENCUMBRANCE_BY_ID_ENDPOINT).withId(transaction.getId()); - return restClient.put(requestEntry, transaction, requestContext); + public Future batchUpdate(List transactions, RequestContext requestContext) { + return batchAllOrNothing(null, transactions, null, null, requestContext); } - public Future updateTransactions(List transactions, RequestContext requestContext) { - return GenericCompositeFuture.join(transactions.stream() - .map(transaction -> updateTransaction(transaction, requestContext)) - .collect(Collectors.toList())) - .mapEmpty(); + public Future batchRelease(List transactions, RequestContext requestContext) { + // NOTE: we will have to use transactionPatches when it is available (see MODORDERS-1008) + transactions.forEach(tr -> tr.getEncumbrance().setStatus(Encumbrance.Status.RELEASED)); + return batchUpdate(transactions, requestContext); } - public Future deleteTransactions(List transactions, RequestContext requestContext) { - // TODO: add semaphores - return GenericCompositeFuture.join(transactions.stream() - .map(transaction -> deleteTransactionById(transaction.getId(), requestContext)) - .collect(Collectors.toList())) - .mapEmpty(); + public Future batchUnrelease(List transactions, RequestContext requestContext) { + // NOTE: we will have to use transactionPatches when it is available (see MODORDERS-1008) + transactions.forEach(tr -> tr.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED)); + return batchUpdate(transactions, requestContext); } - private Future deleteTransactionById(String transactionId, RequestContext requestContext) { - RequestEntry requestEntry = new RequestEntry(ENCUMBRANCE_BY_ID_ENDPOINT).withId(transactionId); - return restClient.delete(requestEntry, requestContext); + public Future batchDelete(List transactionIds, RequestContext requestContext) { + return batchAllOrNothing(null, null, transactionIds, null, requestContext); } + + public Future batchReleaseAndDelete(List transactions, RequestContext requestContext) { + // NOTE: we will have to use transactionPatches when it is available (see MODORDERS-1008) + transactions.forEach(tr -> tr.getEncumbrance().setStatus(Encumbrance.Status.RELEASED)); + List ids = transactions.stream().map(Transaction::getId).toList(); + return batchAllOrNothing(null, transactions, ids, null, requestContext); + } + } diff --git a/src/main/java/org/folio/service/finance/transaction/summary/AbstractTransactionSummariesService.java b/src/main/java/org/folio/service/finance/transaction/summary/AbstractTransactionSummariesService.java deleted file mode 100644 index d215dc5fb..000000000 --- a/src/main/java/org/folio/service/finance/transaction/summary/AbstractTransactionSummariesService.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.folio.service.finance.transaction.summary; - -import io.vertx.core.Future; -import org.folio.rest.core.RestClient; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.core.models.RequestEntry; - -public abstract class AbstractTransactionSummariesService { - - private static final String ENDPOINT = "/finance/%s-transaction-summaries"; - - private static final String GET_BY_ID_STORAGE_ENDPOINT = "/finance-storage/%s-transaction-summaries/{id}"; - - private final RestClient restClient; - - protected AbstractTransactionSummariesService(RestClient restClient) { - this.restClient = restClient; - } - - public Future createTransactionSummary(T summary, RequestContext requestContext) { - RequestEntry requestEntry = new RequestEntry(getEndpoint()); - return restClient.post(requestEntry, summary, getClassT(), requestContext); - } - - public Future getTransactionSummary(String id, RequestContext requestContext) { - RequestEntry requestEntry = new RequestEntry(getStorageEndpointById()).withId(id); - return restClient.get(requestEntry.buildEndpoint(), true, getClassT(), requestContext); - } - - public Future updateTransactionSummary(T summary, RequestContext requestContext) { - int transactionNumber = getTransactionNumber(summary); - if (transactionNumber > 0) { - RequestEntry requestEntry = new RequestEntry(getEndpointById()).withId(getId(summary)); - return restClient.put(requestEntry, summary, requestContext); - } else { - return Future.succeededFuture(); - } - } - - private String getEndpointById() { - return getEndpoint() + "/{id}"; - } - - private String getEndpoint() { - return String.format(ENDPOINT, getSummaryName()); - } - - private String getStorageEndpointById() { - return String.format(GET_BY_ID_STORAGE_ENDPOINT, getSummaryName()); - } - - protected abstract String getId(T summary); - - protected abstract int getTransactionNumber(T summary); - - protected abstract String getSummaryName(); - - protected abstract Class getClassT(); - -} diff --git a/src/main/java/org/folio/service/finance/transaction/summary/InvoiceTransactionSummariesService.java b/src/main/java/org/folio/service/finance/transaction/summary/InvoiceTransactionSummariesService.java deleted file mode 100644 index 703485b42..000000000 --- a/src/main/java/org/folio/service/finance/transaction/summary/InvoiceTransactionSummariesService.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.folio.service.finance.transaction.summary; - -import org.folio.rest.acq.model.finance.InvoiceTransactionSummary; -import org.folio.rest.core.RestClient; - -public class InvoiceTransactionSummariesService extends AbstractTransactionSummariesService { - - private static final String SUMMARY_NAME = "invoice"; - - public InvoiceTransactionSummariesService(RestClient restClient) { - super(restClient); - } - - public static InvoiceTransactionSummary buildInvoiceTransactionsSummary(String invoiceId, int size) { - return new InvoiceTransactionSummary().withId(invoiceId) - .withNumPendingPayments(size).withNumPaymentsCredits(size); - } - - @Override - protected String getId(InvoiceTransactionSummary summary) { - return summary.getId(); - } - - @Override - protected int getTransactionNumber(InvoiceTransactionSummary summary) { - return summary.getNumPaymentsCredits() + summary.getNumPendingPayments(); - } - - @Override - protected String getSummaryName() { - return SUMMARY_NAME; - } - - @Override - protected Class getClassT() { - return InvoiceTransactionSummary.class; - } - -} diff --git a/src/main/java/org/folio/service/finance/transaction/summary/OrderTransactionSummariesService.java b/src/main/java/org/folio/service/finance/transaction/summary/OrderTransactionSummariesService.java deleted file mode 100644 index f73bb2d6f..000000000 --- a/src/main/java/org/folio/service/finance/transaction/summary/OrderTransactionSummariesService.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.folio.service.finance.transaction.summary; - -import java.util.concurrent.CompletionException; -import java.util.stream.Stream; - -import org.apache.commons.collections4.CollectionUtils; -import org.folio.models.EncumbranceRelationsHolder; -import org.folio.models.EncumbrancesProcessingHolder; -import org.folio.orders.utils.HelperUtils; -import org.folio.rest.acq.model.finance.Encumbrance; -import org.folio.rest.acq.model.finance.OrderTransactionSummary; -import org.folio.rest.acq.model.finance.Transaction; -import org.folio.rest.core.RestClient; -import org.folio.rest.core.models.RequestContext; - -import io.vertx.core.Future; - -public class OrderTransactionSummariesService extends AbstractTransactionSummariesService { - - private static final String SUMMARY_NAME = "order"; - - public OrderTransactionSummariesService(RestClient restClient) { - super(restClient); - } - - public Future updateTransactionSummary(String orderId, int number, RequestContext requestContext) { - OrderTransactionSummary summary = new OrderTransactionSummary() - .withId(orderId) - .withNumTransactions(number); - return updateTransactionSummary(summary, requestContext); - } - - public Future updateOrCreateTransactionSummary(String orderId, int number, RequestContext requestContext) { - return getTransactionSummary(orderId, requestContext) - .recover(t -> { - if (HelperUtils.isNotFound(t)) - return null; - throw new CompletionException(t); - }) - .compose(summary -> { - if (summary != null) { - return updateTransactionSummary(orderId, number, requestContext); - } - return createTransactionSummary(new OrderTransactionSummary().withId(orderId).withNumTransactions(number), - requestContext) - .mapEmpty(); - }); - } - - public Future createOrUpdateOrderTransactionSummary(EncumbrancesProcessingHolder holder, RequestContext requestContext) { - Stream orderIdFromCreate = holder.getEncumbrancesForCreate() - .stream() - .map(EncumbranceRelationsHolder::getOrderId); - Stream orderIdFromStorage = holder.getEncumbrancesFromStorage() - .stream() - .map(Transaction::getEncumbrance) - .map(Encumbrance::getSourcePurchaseOrderId); - String orderId = Stream.concat(orderIdFromCreate, orderIdFromStorage) - .findFirst() - .orElse(null); - - // update or create summary if not exists - if (CollectionUtils.isEmpty(holder.getEncumbrancesFromStorage())) { - return updateOrCreateTransactionSummary(orderId, holder.getAllEncumbrancesQuantity(), requestContext); - } else if (holder.getAllEncumbrancesQuantity() == 0) { - return Future.succeededFuture(); - } else { - return updateTransactionSummary(orderId, holder.getAllEncumbrancesQuantity(), requestContext); - } - } - - @Override - protected String getId(OrderTransactionSummary summary) { - return summary.getId(); - } - - @Override - protected int getTransactionNumber(OrderTransactionSummary summary) { - return summary.getNumTransactions(); - } - - @Override - protected String getSummaryName() { - return SUMMARY_NAME; - } - - @Override - protected Class getClassT() { - return OrderTransactionSummary.class; - } - -} diff --git a/src/main/java/org/folio/service/invoice/POLInvoiceLineRelationService.java b/src/main/java/org/folio/service/invoice/POLInvoiceLineRelationService.java index d523d7a55..dab2071de 100644 --- a/src/main/java/org/folio/service/invoice/POLInvoiceLineRelationService.java +++ b/src/main/java/org/folio/service/invoice/POLInvoiceLineRelationService.java @@ -5,7 +5,6 @@ import org.folio.models.EncumbranceRelationsHolder; import org.folio.models.EncumbrancesProcessingHolder; import org.folio.models.PoLineInvoiceLineHolder; -import org.folio.okapi.common.GenericCompositeFuture; import org.folio.orders.utils.HelperUtils; import org.folio.rest.acq.model.finance.Encumbrance; import org.folio.rest.acq.model.finance.Transaction; @@ -18,28 +17,27 @@ import io.vertx.core.Future; import org.folio.service.finance.transaction.PendingPaymentService; -import org.folio.service.finance.transaction.summary.InvoiceTransactionSummariesService; +import org.folio.service.finance.transaction.TransactionService; import javax.money.Monetary; import java.math.BigDecimal; import java.util.List; import java.util.stream.Collectors; -import static java.util.stream.Collectors.groupingBy; -import static org.folio.service.finance.transaction.summary.InvoiceTransactionSummariesService.buildInvoiceTransactionsSummary; import static org.folio.service.invoice.PoLineInvoiceLineHolderBuilder.filterInvoiceLinesByStatuses; public class POLInvoiceLineRelationService { private final InvoiceLineService invoiceLineService; private final PendingPaymentService pendingPaymentService; - private final InvoiceTransactionSummariesService invoiceTransactionSummariesService; private final PoLineInvoiceLineHolderBuilder poLineInvoiceLineHolderBuilder; + private final TransactionService transactionService; - public POLInvoiceLineRelationService(InvoiceLineService invoiceLineService, PendingPaymentService pendingPaymentService, InvoiceTransactionSummariesService invoiceTransactionSummariesService, PoLineInvoiceLineHolderBuilder poLineInvoiceLineHolderBuilder) { + public POLInvoiceLineRelationService(InvoiceLineService invoiceLineService, PendingPaymentService pendingPaymentService, + PoLineInvoiceLineHolderBuilder poLineInvoiceLineHolderBuilder, TransactionService transactionService) { this.invoiceLineService = invoiceLineService; this.pendingPaymentService = pendingPaymentService; - this.invoiceTransactionSummariesService = invoiceTransactionSummariesService; this.poLineInvoiceLineHolderBuilder = poLineInvoiceLineHolderBuilder; + this.transactionService = transactionService; } public Future prepareRelatedInvoiceLines(PoLineInvoiceLineHolder holder, RequestContext requestContext) { @@ -92,15 +90,14 @@ public Future updateInvoiceLineReference(PoLineInvoiceLineHolder holder, R private Future removeEncumbranceReferenceFromTransactions(List encumbranceIds, RequestContext requestContext) { return pendingPaymentService.getTransactionsByEncumbranceIds(encumbranceIds, requestContext) - .map(pendingPayments -> pendingPayments.stream().map(transaction -> { - transaction.getAwaitingPayment().setEncumbranceId(null); - return transaction; - }).collect(groupingBy(Transaction::getSourceInvoiceId))) - .map(pendingPayments -> pendingPayments.entrySet().stream().map(entry -> - invoiceTransactionSummariesService.updateTransactionSummary(buildInvoiceTransactionsSummary(entry.getKey(), entry.getValue().size()), requestContext) - .compose(aVoid -> pendingPaymentService.updateTransactions(entry.getValue(),requestContext))).collect(Collectors.toList())) - .compose(GenericCompositeFuture::join) - .mapEmpty(); + .compose(pendingPayments -> { + if (pendingPayments.isEmpty()) { + return Future.succeededFuture(); + } + pendingPayments.forEach(pp -> pp.getAwaitingPayment().setEncumbranceId(null)); + return transactionService.batchUpdate(pendingPayments, requestContext) + .mapEmpty(); + }); } private static org.folio.rest.acq.model.invoice.FundDistribution convertToInvoiceFundDistribution(FundDistribution fundDistribution) { diff --git a/src/main/java/org/folio/service/orders/OrderReEncumberService.java b/src/main/java/org/folio/service/orders/OrderReEncumberService.java index db44cb351..c7d66a0bb 100644 --- a/src/main/java/org/folio/service/orders/OrderReEncumberService.java +++ b/src/main/java/org/folio/service/orders/OrderReEncumberService.java @@ -46,7 +46,6 @@ import org.folio.service.finance.rollover.LedgerRolloverErrorService; import org.folio.service.finance.rollover.LedgerRolloverProgressService; import org.folio.service.finance.transaction.TransactionService; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.javamoney.moneta.Money; import org.javamoney.moneta.function.MonetaryOperators; @@ -63,7 +62,6 @@ public class OrderReEncumberService implements CompositeOrderDynamicDataPopulate private final LedgerRolloverProgressService ledgerRolloverProgressService; private final PurchaseOrderLineService purchaseOrderLineService; private final TransactionService transactionService; - private final OrderTransactionSummariesService orderTransactionSummariesService; private final BudgetRestrictionService budgetRestrictionService; public OrderReEncumberService(PurchaseOrderStorageService purchaseOrderStorageService, @@ -71,7 +69,6 @@ public OrderReEncumberService(PurchaseOrderStorageService purchaseOrderStorageSe LedgerRolloverErrorService ledgerRolloverErrorService, LedgerRolloverProgressService ledgerRolloverProgressService, PurchaseOrderLineService purchaseOrderLineService, TransactionService transactionService, - OrderTransactionSummariesService orderTransactionSummariesService, BudgetRestrictionService budgetRestrictionService) { this.purchaseOrderStorageService = purchaseOrderStorageService; this.reEncumbranceHoldersBuilder = reEncumbranceHoldersBuilder; @@ -79,7 +76,6 @@ public OrderReEncumberService(PurchaseOrderStorageService purchaseOrderStorageSe this.ledgerRolloverProgressService = ledgerRolloverProgressService; this.purchaseOrderLineService = purchaseOrderLineService; this.transactionService = transactionService; - this.orderTransactionSummariesService = orderTransactionSummariesService; this.budgetRestrictionService = budgetRestrictionService; } @@ -284,21 +280,12 @@ private Future> validateAndCreateEncumbrances(List { - - String orderId = purchaseOrder.getId(); - return orderTransactionSummariesService.updateTransactionSummary(orderId, holderForCreateEncumbrances.size(), requestContext) - .compose(aVoid -> GenericCompositeFuture.join(holderForCreateEncumbrances.stream() - .map(holder -> transactionService.createTransaction(holder.getNewEncumbrance(), requestContext) - .onSuccess(holder::withNewEncumbrance)) - .toList())) - .map(aVoid -> holders); - }) - .orElseGet(() -> Future.succeededFuture(holders)); - + List encumbrances = holderForCreateEncumbrances.stream().map(ReEncumbranceHolder::getNewEncumbrance).toList(); + if (encumbrances.isEmpty()) { + return Future.succeededFuture(holders); + } + return transactionService.batchCreate(encumbrances, requestContext) + .map(aVoid -> holders); } } diff --git a/src/main/java/org/folio/service/orders/OrderRolloverService.java b/src/main/java/org/folio/service/orders/OrderRolloverService.java index 89b0a60dc..3e1111f26 100644 --- a/src/main/java/org/folio/service/orders/OrderRolloverService.java +++ b/src/main/java/org/folio/service/orders/OrderRolloverService.java @@ -280,7 +280,8 @@ private Future> removeEncumbrancesFromClosedPoLines(List po if (transactions.isEmpty()) { return Future.succeededFuture(); } else { - return transactionService.deleteTransactions(transactions, requestContext); + List idsOfTransactionsToDelete = transactions.stream().map(Transaction::getId).toList(); + return transactionService.batchDelete(idsOfTransactionsToDelete, requestContext); } }) .map(v -> removeEncumbranceLinks(poLines)); diff --git a/src/test/java/org/folio/ApiTestSuite.java b/src/test/java/org/folio/ApiTestSuite.java index d2aefbb72..9fb25b0d2 100644 --- a/src/test/java/org/folio/ApiTestSuite.java +++ b/src/test/java/org/folio/ApiTestSuite.java @@ -59,7 +59,6 @@ import org.folio.service.finance.transaction.OpenToPendingEncumbranceStrategyTest; import org.folio.service.finance.transaction.PendingToOpenEncumbranceStrategyTest; import org.folio.service.finance.transaction.TransactionServiceTest; -import org.folio.service.finance.transaction.TransactionSummariesServiceTest; import org.folio.service.inventory.HoldingsSummaryServiceTest; import org.folio.service.inventory.InventoryManagerTest; import org.folio.service.invoice.InvoiceLineServiceTest; @@ -455,10 +454,6 @@ class LedgerRolloverErrorServiceTestNested extends LedgerRolloverErrorServiceTes class LedgerRolloverProgressServiceTestNested extends LedgerRolloverProgressServiceTest { } - @Nested - class TransactionSummariesServiceTestNested extends TransactionSummariesServiceTest { - } - @Nested class ClosedToOpenEncumbranceStrategyTestNested extends ClosedToOpenEncumbranceStrategyTest { } diff --git a/src/test/java/org/folio/rest/impl/MockServer.java b/src/test/java/org/folio/rest/impl/MockServer.java index 2a58d74c1..58626f43a 100644 --- a/src/test/java/org/folio/rest/impl/MockServer.java +++ b/src/test/java/org/folio/rest/impl/MockServer.java @@ -57,11 +57,10 @@ import static org.folio.orders.utils.ResourcePathResolver.ALERTS; import static org.folio.orders.utils.ResourcePathResolver.BUDGETS; import static org.folio.orders.utils.ResourcePathResolver.CURRENT_BUDGET; -import static org.folio.orders.utils.ResourcePathResolver.ENCUMBRANCES; import static org.folio.orders.utils.ResourcePathResolver.EXPENSE_CLASSES_URL; import static org.folio.orders.utils.ResourcePathResolver.EXPORT_HISTORY; +import static org.folio.orders.utils.ResourcePathResolver.FINANCE_BATCH_TRANSACTIONS; import static org.folio.orders.utils.ResourcePathResolver.FINANCE_EXCHANGE_RATE; -import static org.folio.orders.utils.ResourcePathResolver.FINANCE_RELEASE_ENCUMBRANCE; import static org.folio.orders.utils.ResourcePathResolver.FUNDS; import static org.folio.orders.utils.ResourcePathResolver.LEDGERS; import static org.folio.orders.utils.ResourcePathResolver.USER_TENANTS_ENDPOINT; @@ -69,7 +68,6 @@ import static org.folio.orders.utils.ResourcePathResolver.LEDGER_FY_ROLLOVER_ERRORS; import static org.folio.orders.utils.ResourcePathResolver.ORDER_INVOICE_RELATIONSHIP; import static org.folio.orders.utils.ResourcePathResolver.ORDER_TEMPLATES; -import static org.folio.orders.utils.ResourcePathResolver.ORDER_TRANSACTION_SUMMARIES; import static org.folio.orders.utils.ResourcePathResolver.PIECES_STORAGE; import static org.folio.orders.utils.ResourcePathResolver.PO_LINES_STORAGE; import static org.folio.orders.utils.ResourcePathResolver.PO_LINE_NUMBER; @@ -93,7 +91,6 @@ import static org.folio.rest.impl.PoNumberApiTest.EXISTING_PO_NUMBER; import static org.folio.rest.impl.PoNumberApiTest.NONEXISTING_PO_NUMBER; import static org.folio.rest.impl.PurchaseOrdersApiTest.ACTIVE_VENDOR_ID; -import static org.folio.rest.impl.PurchaseOrdersApiTest.FUND_ENCUMBRANCE_ERROR; import static org.folio.rest.impl.PurchaseOrdersApiTest.ID_FOR_PRINT_MONOGRAPH_ORDER; import static org.folio.rest.impl.PurchaseOrdersApiTest.INACTIVE_VENDOR_ID; import static org.folio.rest.impl.PurchaseOrdersApiTest.ITEMS_NOT_FOUND; @@ -123,6 +120,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -160,6 +158,7 @@ import org.folio.rest.acq.model.SequenceNumbers; import org.folio.rest.acq.model.Title; import org.folio.rest.acq.model.TitleCollection; +import org.folio.rest.acq.model.finance.Batch; import org.folio.rest.acq.model.finance.Budget; import org.folio.rest.acq.model.finance.BudgetCollection; import org.folio.rest.acq.model.finance.BudgetExpenseClassCollection; @@ -171,7 +170,7 @@ import org.folio.rest.acq.model.finance.FundCollection; import org.folio.rest.acq.model.finance.Ledger; import org.folio.rest.acq.model.finance.LedgerCollection; -import org.folio.rest.acq.model.finance.OrderTransactionSummary; +import org.folio.rest.acq.model.finance.Metadata; import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.acq.model.finance.TransactionCollection; import org.folio.rest.acq.model.invoice.FundDistribution; @@ -459,27 +458,28 @@ public static List getAcqMembershipsSearches() { } public static List getCreatedEncumbrances() { - List jsonObjects = serverRqRs.get(ENCUMBRANCES, HttpMethod.POST); + List jsonObjects = serverRqRs.get(FINANCE_BATCH_TRANSACTIONS, HttpMethod.POST); return jsonObjects == null ? Collections.emptyList() : jsonObjects.stream() - .map(json -> json.mapTo(Transaction.class)) - .collect(Collectors.toList()); + .map(json -> json.mapTo(Batch.class)) + .map(Batch::getTransactionsToCreate) + .flatMap(Collection::stream) + .toList(); } public static List getUpdatedTransactions() { - List jsonObjects = serverRqRs.get(ENCUMBRANCES, HttpMethod.PUT); + List jsonObjects = serverRqRs.get(FINANCE_BATCH_TRANSACTIONS, HttpMethod.POST); return jsonObjects == null ? Collections.emptyList() : jsonObjects.stream() - .map(json -> json.mapTo(Transaction.class)) - .collect(Collectors.toList()); + .map(json -> json.mapTo(Batch.class)) + .map(Batch::getTransactionsToUpdate) + .flatMap(Collection::stream) + .toList(); } - static List getCreatedOrderSummaries() { - return Optional.ofNullable(serverRqRs.get(ORDER_TRANSACTION_SUMMARIES, HttpMethod.POST)).orElse(Collections.emptyList()); - } - - static List getExistingOrderSummaries() { - return Optional.ofNullable(serverRqRs.get(ORDER_TRANSACTION_SUMMARIES, HttpMethod.PUT)).orElse(Collections.emptyList()); + static List getBatchCalls() { + return Optional.ofNullable(serverRqRs.get(FINANCE_BATCH_TRANSACTIONS, HttpMethod.POST)) + .orElse(Collections.emptyList()); } private static List getCollectionRecords(List entries) { @@ -542,10 +542,8 @@ private Router defineRoutes() { router.post(resourcesPath(REPORTING_CODES)).handler(ctx -> handlePostGenericSubObj(ctx, REPORTING_CODES)); router.post(resourcesPath(PIECES_STORAGE)).handler(ctx -> handlePostGenericSubObj(ctx, PIECES_STORAGE)); router.post(resourcesPath(ORDER_TEMPLATES)).handler(ctx -> handlePostGenericSubObj(ctx, ORDER_TEMPLATES)); - router.post(resourcesPath(ENCUMBRANCES)).handler(this::handleTransactionPostEntry); + router.post(resourcesPath(FINANCE_BATCH_TRANSACTIONS)).handler(this::handleBatchTransactions); router.post(resourcesPath(TITLES)).handler(ctx -> handlePostGenericSubObj(ctx, TITLES)); - router.post(resourcesPath(ORDER_TRANSACTION_SUMMARIES)).handler(ctx -> handlePostGenericSubObj(ctx, ORDER_TRANSACTION_SUMMARIES)); - router.post("/finance/release-encumbrance/:id").handler(ctx -> handlePostGenericSubObj(ctx, FINANCE_RELEASE_ENCUMBRANCE)); router.post(resourcesPath(ACQUISITIONS_UNITS)).handler(ctx -> handlePostGenericSubObj(ctx, ACQUISITIONS_UNITS)); router.post(resourcesPath(ACQUISITION_METHODS)).handler(ctx -> handlePostGenericSubObj(ctx, ACQUISITION_METHODS)); @@ -636,8 +634,6 @@ private Router defineRoutes() { router.put(resourcePath(REASONS_FOR_CLOSURE)).handler(ctx -> handlePutGenericSubObj(ctx, REASONS_FOR_CLOSURE)); router.put(resourcePath(PREFIXES)).handler(ctx -> handlePutGenericSubObj(ctx, PREFIXES)); router.put(resourcePath(SUFFIXES)).handler(ctx -> handlePutGenericSubObj(ctx, SUFFIXES)); - router.put("/finance/order-transaction-summaries/:id").handler(ctx -> handlePutGenericSubObj(ctx, ORDER_TRANSACTION_SUMMARIES)); - router.put(resourcePath(ENCUMBRANCES)).handler(ctx -> handlePutGenericSubObj(ctx, ENCUMBRANCES)); router.put(resourcePath(ACQUISITION_METHODS)).handler(ctx -> handlePutGenericSubObj(ctx, ACQUISITION_METHODS)); @@ -650,7 +646,6 @@ private Router defineRoutes() { router.delete(resourcePath(ACQUISITION_METHODS)).handler(ctx -> handleDeleteGenericSubObj(ctx, ACQUISITION_METHODS)); router.delete(resourcePath(ACQUISITIONS_MEMBERSHIPS)).handler(ctx -> handleDeleteGenericSubObj(ctx, ACQUISITIONS_MEMBERSHIPS)); router.delete(resourcePath(ORDER_TEMPLATES)).handler(ctx -> handleDeleteGenericSubObj(ctx, ORDER_TEMPLATES)); - router.delete(resourcePath(ENCUMBRANCES)).handler(ctx -> handleDeleteGenericSubObj(ctx, ENCUMBRANCES)); router.delete(resourcePath(TITLES)).handler(ctx -> handleDeleteGenericSubObj(ctx, TITLES)); router.delete(resourcePath(REASONS_FOR_CLOSURE)).handler(ctx -> handleDeleteGenericSubObj(ctx, REASONS_FOR_CLOSURE)); router.delete(resourcePath(PREFIXES)).handler(ctx -> handleDeleteGenericSubObj(ctx, PREFIXES)); @@ -2185,75 +2180,45 @@ private void handlePostGenericSubObj(RoutingContext ctx, String subObj) { serverResponse(ctx, status, contentType, respBody); } - private void handleTransactionPostEntry(RoutingContext ctx) { - logger.info("got: " + ctx.body().asString()); - - String echoStatus = ctx.request().getHeader(X_ECHO_STATUS); - - if (echoStatus != null && !echoStatus.equals("201")){ - int status; - String respBody = ""; - try { - status = Integer.parseInt(echoStatus); - switch (status) { - case 400 -> respBody = "Unable to add -- malformed JSON at 13:3"; - case 403 -> respBody = "Access requires permission: foo.bar.baz"; - case 500 -> respBody = INTERNAL_SERVER_ERROR.getReasonPhrase(); - } - serverResponse(ctx, status, APPLICATION_JSON, respBody); - return; - - } catch (NumberFormatException e) { - logger.error("Exception parsing " + X_ECHO_STATUS, e); - } - - } + private void handleBatchTransactions(RoutingContext ctx) { + logger.info("handleBatchTransactions got: " + ctx.request().path()); String tenant = ctx.request().getHeader(OKAPI_HEADER_TENANT); if (INTERNAL_SERVER_ERROR.getReasonPhrase().equals(tenant)) { serverResponse(ctx, 500, TEXT_PLAIN, Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase()); - } else if (FUND_CANNOT_BE_PAID_TENANT.equals(tenant)){ + + } else if (FUND_CANNOT_BE_PAID_TENANT.equals(tenant)) { Errors errors = new Errors(); List errorList = new ArrayList<>(); errorList.add(new Error().withCode(FUND_CANNOT_BE_PAID.getCode()).withMessage(FUND_CANNOT_BE_PAID.getDescription())); errors.withErrors(errorList); - serverResponse(ctx, 422, APPLICATION_JSON, JsonObject.mapFrom(errors).encodePrettily()); - } else if (BUDGET_IS_INACTIVE_TENANT.equals(tenant) || ctx.body().asJsonObject().getString("fromFundId").equals(FUND_ENCUMBRANCE_ERROR)){ + } else if (BUDGET_IS_INACTIVE_TENANT.equals(tenant)) { Errors errors = new Errors(); List errorList = new ArrayList<>(); errorList.add(new Error().withCode(BUDGET_IS_INACTIVE.getCode()).withMessage(BUDGET_IS_INACTIVE.getDescription())); errors.withErrors(errorList); - serverResponse(ctx, 422, APPLICATION_JSON, JsonObject.mapFrom(errors).encodePrettily()); - } else if (LEDGER_NOT_FOUND_FOR_TRANSACTION_TENANT.equals(tenant)){ + } else if (LEDGER_NOT_FOUND_FOR_TRANSACTION_TENANT.equals(tenant)) { Errors errors = new Errors(); List errorList = new ArrayList<>(); errorList.add(new Error().withCode(LEDGER_NOT_FOUND_FOR_TRANSACTION.getCode()).withMessage(LEDGER_NOT_FOUND_FOR_TRANSACTION.getDescription())); errors.withErrors(errorList); - serverResponse(ctx, 422, APPLICATION_JSON, JsonObject.mapFrom(errors).encodePrettily()); - } else if (BUDGET_NOT_FOUND_FOR_TRANSACTION_TENANT.equals(tenant)){ + } else if (BUDGET_NOT_FOUND_FOR_TRANSACTION_TENANT.equals(tenant)) { Errors errors = new Errors(); List errorList = new ArrayList<>(); errorList.add(new Error().withCode(BUDGET_NOT_FOUND_FOR_TRANSACTION.getCode()).withMessage(BUDGET_NOT_FOUND_FOR_TRANSACTION.getDescription())); errors.withErrors(errorList); - serverResponse(ctx, 422, APPLICATION_JSON, JsonObject.mapFrom(errors).encodePrettily()); } else { - JsonObject body = ctx.body().asJsonObject(); - if (body.getString(ID) == null) { - body.put(ID, UUID.randomUUID().toString()); - } - - addServerRqRsData(HttpMethod.POST, ENCUMBRANCES, body); - serverResponse(ctx, 201, APPLICATION_JSON, JsonObject.mapFrom(body) - .encodePrettily()); + addServerRqRsData(HttpMethod.POST, FINANCE_BATCH_TRANSACTIONS, ctx.body().asJsonObject()); + serverResponse(ctx, 204, TEXT_PLAIN, ""); } } @@ -2272,14 +2237,16 @@ private void handleTransactionGetEntry(RoutingContext ctx) { .withEncumbrance(new Encumbrance() .withSourcePurchaseOrderId("d6966317-96c7-492f-8df6-dc6c19554452") .withSourcePoLineId("a6edc906-2f9f-5fb2-a373-efac406f0ef2") - .withStatus(Encumbrance.Status.UNRELEASED)); + .withStatus(Encumbrance.Status.UNRELEASED)) + .withMetadata(new Metadata()); Transaction transaction2 = new Transaction() .withId(UUID.randomUUID().toString()) .withFromFundId("fb7b70f1-b898-4924-a991-0e4b6312bb5f") .withEncumbrance(new Encumbrance() .withSourcePurchaseOrderId("d6966317-96c7-492f-8df6-dc6c19554452") .withSourcePoLineId("a6edc906-2f9f-5fb2-a373-efac406f0ef2") - .withStatus(Encumbrance.Status.UNRELEASED)); + .withStatus(Encumbrance.Status.UNRELEASED)) + .withMetadata(new Metadata()); List transactions = List.of(transaction1); TransactionCollection transactionCollection = new TransactionCollection().withTransactions(List.of(transaction1, transaction2)).withTotalRecords(2); body = JsonObject.mapFrom(transactionCollection).encodePrettily(); @@ -2291,7 +2258,8 @@ private void handleTransactionGetEntry(RoutingContext ctx) { .withEncumbrance(new Encumbrance() .withSourcePurchaseOrderId("477f9ca8-b295-11eb-8529-0242ac130003") .withSourcePoLineId("50fb5514-cdf1-11e8-a8d5-f2801f1b9fd1") - .withStatus(Encumbrance.Status.RELEASED)); + .withStatus(Encumbrance.Status.RELEASED)) + .withMetadata(new Metadata()); List transactions = List.of(transaction1); TransactionCollection transactionCollection = new TransactionCollection().withTransactions(transactions).withTotalRecords(1); body = JsonObject.mapFrom(transactionCollection).encodePrettily(); @@ -2327,8 +2295,6 @@ private Class getSubObjClass(String subObj) { case ACQUISITION_METHODS -> AcquisitionMethod.class; case ACQUISITIONS_MEMBERSHIPS -> AcquisitionsUnitMembership.class; case ORDER_TEMPLATES -> OrderTemplate.class; - case ORDER_TRANSACTION_SUMMARIES -> OrderTransactionSummary.class; - case ENCUMBRANCES -> Transaction.class; case TITLES -> Title.class; case REASONS_FOR_CLOSURE -> ReasonForClosure.class; case PREFIXES -> Prefix.class; diff --git a/src/test/java/org/folio/rest/impl/PurchaseOrderLinesApiTest.java b/src/test/java/org/folio/rest/impl/PurchaseOrderLinesApiTest.java index ea8482648..35bca5d3e 100644 --- a/src/test/java/org/folio/rest/impl/PurchaseOrderLinesApiTest.java +++ b/src/test/java/org/folio/rest/impl/PurchaseOrderLinesApiTest.java @@ -43,9 +43,8 @@ import static org.folio.orders.utils.ResourcePathResolver.ACQUISITIONS_MEMBERSHIPS; import static org.folio.orders.utils.ResourcePathResolver.ACQUISITIONS_UNITS; import static org.folio.orders.utils.ResourcePathResolver.ALERTS; -import static org.folio.orders.utils.ResourcePathResolver.ENCUMBRANCES; +import static org.folio.orders.utils.ResourcePathResolver.FINANCE_BATCH_TRANSACTIONS; import static org.folio.orders.utils.ResourcePathResolver.FUNDS; -import static org.folio.orders.utils.ResourcePathResolver.ORDER_TRANSACTION_SUMMARIES; import static org.folio.orders.utils.ResourcePathResolver.PIECES_STORAGE; import static org.folio.orders.utils.ResourcePathResolver.PO_LINES_STORAGE; import static org.folio.orders.utils.ResourcePathResolver.PO_NUMBER; @@ -678,8 +677,12 @@ void testPutOrderLineByIdWithoutOrderUpdate() { assertThat(column, hasKey(PO_LINES_STORAGE)); column = MockServer.serverRqRs.column(HttpMethod.PUT); - assertEquals(5, column.size()); - assertThat(column.keySet(), containsInAnyOrder(PO_LINES_STORAGE, ALERTS, REPORTING_CODES, ORDER_TRANSACTION_SUMMARIES, ENCUMBRANCES)); + assertEquals(3, column.size()); + assertThat(column.keySet(), containsInAnyOrder(PO_LINES_STORAGE, ALERTS, REPORTING_CODES)); + + column = MockServer.serverRqRs.column(HttpMethod.POST); + assertEquals(1, column.size()); + assertThat(column.keySet(), containsInAnyOrder(FINANCE_BATCH_TRANSACTIONS)); // Verify no message sent via event bus HandlersTestHelper.verifyOrderStatusUpdateEvent(0); @@ -1194,7 +1197,8 @@ void testUpdatePolineForOpenedOrderWithChangingCost() { verifyPut(String.format(LINE_BY_ID_PATH, reqData.getId()), JsonObject.mapFrom(reqData).encode(), prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID), "", 204); - assertThat("One or more transactions have been updated", MockServer.getRqRsEntries(HttpMethod.PUT, ENCUMBRANCES).size() > 0); + assertThat("One or more transactions have been updated", + !MockServer.getRqRsEntries(HttpMethod.POST, FINANCE_BATCH_TRANSACTIONS).isEmpty()); } @Test @@ -1286,9 +1290,8 @@ void testUpdatePolineForOpenedOrderWithoutUpdatingEncumbrances() { verifyPut(String.format(LINE_BY_ID_PATH, reqData.getId()), JsonObject.mapFrom(reqData).encode(), prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID), "", 204); - assertThat("No transactions have been created", MockServer.getRqRsEntries(HttpMethod.POST, ENCUMBRANCES).size() == 0); - assertThat("No transactions have been updated", MockServer.getRqRsEntries(HttpMethod.PUT, ENCUMBRANCES).size() == 0); - assertThat("No transactions have been deleted", MockServer.getRqRsEntries(HttpMethod.DELETE, ENCUMBRANCES).size() == 0); + assertThat("No transaction has been created, updated or deleted", + MockServer.getRqRsEntries(HttpMethod.POST, FINANCE_BATCH_TRANSACTIONS).isEmpty()); // double check with updating status only (When only status updated via request from mod-invoices) CompositePoLine updatedLine = getRqRsEntries(HttpMethod.PUT, PO_LINES_STORAGE).get(0).mapTo(CompositePoLine.class); @@ -1297,10 +1300,8 @@ void testUpdatePolineForOpenedOrderWithoutUpdatingEncumbrances() { verifyPut(String.format(LINE_BY_ID_PATH, reqData.getId()), JsonObject.mapFrom(updatedLine).encodePrettily(), prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID), "", 204); - assertThat("No transactions have been created", MockServer.getRqRsEntries(HttpMethod.POST, ENCUMBRANCES).size() == 0); - assertThat("No transactions have been updated", MockServer.getRqRsEntries(HttpMethod.PUT, ENCUMBRANCES).size() == 0); - assertThat("No transactions have been deleted", MockServer.getRqRsEntries(HttpMethod.DELETE, ENCUMBRANCES).size() == 0); - + assertThat("No transaction has been created, updated or deleted", + MockServer.getRqRsEntries(HttpMethod.POST, FINANCE_BATCH_TRANSACTIONS).isEmpty()); } @Test diff --git a/src/test/java/org/folio/rest/impl/PurchaseOrdersApiTest.java b/src/test/java/org/folio/rest/impl/PurchaseOrdersApiTest.java index 38544c15a..d9d93b516 100644 --- a/src/test/java/org/folio/rest/impl/PurchaseOrdersApiTest.java +++ b/src/test/java/org/folio/rest/impl/PurchaseOrdersApiTest.java @@ -82,14 +82,13 @@ import static org.folio.rest.impl.MockServer.LEDGER_NOT_FOUND_FOR_TRANSACTION_TENANT; import static org.folio.rest.impl.MockServer.PO_LINES_EMPTY_COLLECTION_ID; import static org.folio.rest.impl.MockServer.addMockEntry; +import static org.folio.rest.impl.MockServer.getBatchCalls; import static org.folio.rest.impl.MockServer.getContributorNameTypesSearches; import static org.folio.rest.impl.MockServer.getCreatedEncumbrances; import static org.folio.rest.impl.MockServer.getCreatedHoldings; import static org.folio.rest.impl.MockServer.getCreatedInstances; import static org.folio.rest.impl.MockServer.getCreatedItems; -import static org.folio.rest.impl.MockServer.getCreatedOrderSummaries; import static org.folio.rest.impl.MockServer.getCreatedPieces; -import static org.folio.rest.impl.MockServer.getExistingOrderSummaries; import static org.folio.rest.impl.MockServer.getHoldingsSearches; import static org.folio.rest.impl.MockServer.getInstanceStatusesSearches; import static org.folio.rest.impl.MockServer.getInstanceTypesSearches; @@ -100,6 +99,7 @@ import static org.folio.rest.impl.MockServer.getPieceSearches; import static org.folio.rest.impl.MockServer.getPurchaseOrderUpdates; import static org.folio.rest.impl.MockServer.getQueryParams; +import static org.folio.rest.impl.MockServer.getUpdatedTransactions; import static org.folio.rest.jaxrs.model.Piece.Format.ELECTRONIC; import static org.folio.rest.jaxrs.model.Piece.Format.OTHER; import static org.folio.rest.jaxrs.model.Piece.Format.PHYSICAL; @@ -125,7 +125,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import java.io.IOException; @@ -210,8 +210,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import io.restassured.http.Header; import io.restassured.http.Headers; @@ -255,7 +253,6 @@ public class PurchaseOrdersApiTest { private static final String ORDER_WITHOUT_WORKFLOW_STATUS = "41d56e59-46db-4d5e-a1ad-a178228913e5"; static final String ORDER_WIT_PO_LINES_FOR_SORTING = "9a952cd0-842b-4e71-bddd-014eb128dc8e"; static final String VALID_FUND_ID = "fb7b70f1-b898-4924-a991-0e4b6312bb5f"; - static final String FUND_ENCUMBRANCE_ERROR = "f1654bbe-dd76-4bfe-a96a-e764141e6aac"; static final String SAMPLE_TITLE_ID = "5489d159-cbbd-417e-a4e3-c6b0f7627f4f"; public static final String ORDER_WITHOUT_MATERIAL_TYPES_ID = "0cb6741d-4a00-47e5-a902-5678eb24478d"; @@ -863,7 +860,7 @@ void testListedPrintMonographInOpenStatus() throws Exception { verifyOpenOrderPiecesCreated(items, resp.getCompositePoLines(), createdPieces, 0); verifyEncumbrancesOnPoCreation(reqData, resp); - assertThat(getExistingOrderSummaries(), hasSize(0)); + assertThat(getUpdatedTransactions(), hasSize(0)); verifyCalculatedData(resp); verifyReceiptStatusChangedTo(CompositePoLine.ReceiptStatus.PARTIALLY_RECEIVED.value(), reqData.getCompositePoLines().size()); verifyPaymentStatusChangedTo(CompositePoLine.PaymentStatus.AWAITING_PAYMENT.value(), reqData.getCompositePoLines().size()); @@ -959,7 +956,7 @@ void testPostListedPrintSerialInOpenStatus() throws Exception { }); verifyEncumbrancesOnPoCreation(reqData, resp); - assertThat(getExistingOrderSummaries(), hasSize(0)); + assertThat(getBatchCalls(), hasSize(0)); verifyCalculatedData(resp); // MODORDERS-459 - check status changed to ONGOING @@ -1283,7 +1280,7 @@ void testPutOrdersByIdPEMixFormat() { verifyOpenOrderPiecesCreated(createdItems, compPo.getCompositePoLines(), createdPieces, 0); verifyEncumbrancesOnPoUpdate(compPo); - assertTrue(getExistingOrderSummaries().size() > 0); + assertFalse(getBatchCalls().isEmpty()); } @Test @@ -1382,7 +1379,6 @@ void testPutOrdersByIdEmptyFundDistributions() { preparePiecesForCompositePo(reqData); verifyPut(String.format(COMPOSITE_ORDERS_BY_ID_PATH, reqData.getId()), JsonObject.mapFrom(reqData), "", 204); - assertThat(getCreatedOrderSummaries(), hasSize(0)); assertThat(getCreatedEncumbrances(), hasSize(0)); } @@ -4281,16 +4277,17 @@ void testReopenOrderUnreleasesEncumbrancesUnlessInvoiceLineHasReleaseEncumbrance PurchaseOrder po = getPurchaseOrderUpdates().get(0).mapTo(PurchaseOrder.class); assertThat(po.getWorkflowStatus(), is(PurchaseOrder.WorkflowStatus.OPEN)); - List transactions = Arrays.asList(transaction); - TransactionCollection transactionCollection = new TransactionCollection().withTransactions(Arrays.asList(transaction)).withTotalRecords(1); - doAnswer(new Answer() { - public Void answer(InvocationOnMock invocation) { - Object[] args = invocation.getArguments(); - return null; - } - }).when(transactionService).updateTransactions(transactions, requestContext); - doReturn(succeededFuture(transactionCollection)).when(restClient).get(requestEntry, TransactionCollection.class, requestContext); - doReturn(succeededFuture(transactions)).when(transactionService).getTransactionsByIds(transactionIds, requestContext); + List transactions = List.of(transaction); + TransactionCollection transactionCollection = new TransactionCollection() + .withTransactions(List.of(transaction)) + .withTotalRecords(1); + doReturn(succeededFuture()) + .when(transactionService).batchUpdate(eq(transactions), eq(requestContext)); + doReturn(succeededFuture(transactionCollection)) + .when(restClient).get(eq(requestEntry), eq(TransactionCollection.class), eq(requestContext)); + doReturn(succeededFuture(transactions)) + .when(transactionService).getTransactionsByIds(eq(transactionIds), eq(requestContext)); + Future> future = encumbranceService.getEncumbrancesByIds(transactionIds, requestContext); vertxTestContext.assertComplete(future) diff --git a/src/test/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilderTest.java b/src/test/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilderTest.java index 0f4bc0e0f..eb42383fc 100644 --- a/src/test/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilderTest.java +++ b/src/test/java/org/folio/service/finance/transaction/EncumbranceRelationsHoldersBuilderTest.java @@ -41,6 +41,7 @@ import org.folio.rest.acq.model.finance.FiscalYear; import org.folio.rest.acq.model.finance.Fund; import org.folio.rest.acq.model.finance.Ledger; +import org.folio.rest.acq.model.finance.Metadata; import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.core.exceptions.HttpException; import org.folio.rest.core.models.RequestContext; @@ -276,7 +277,8 @@ void testShouldPopulateHoldersWithOldEncumbranceIfMatchesTransactionFromStorage( .withInitialAmountEncumbered(68d) .withAmountExpended(10d) .withAmountAwaitingPayment(20d) - ); + ) + .withMetadata(new Metadata()); List holders = new ArrayList<>(); holders.add(holder1); diff --git a/src/test/java/org/folio/service/finance/transaction/EncumbranceServiceTest.java b/src/test/java/org/folio/service/finance/transaction/EncumbranceServiceTest.java index 36df69c50..860c904a5 100644 --- a/src/test/java/org/folio/service/finance/transaction/EncumbranceServiceTest.java +++ b/src/test/java/org/folio/service/finance/transaction/EncumbranceServiceTest.java @@ -7,12 +7,9 @@ import static org.folio.TestUtils.getMockAsJson; import static org.folio.rest.RestConstants.OKAPI_URL; import static org.folio.rest.RestVerticle.OKAPI_HEADER_TENANT; -import static org.folio.rest.impl.MockServer.BASE_MOCK_DATA_PATH; import static org.folio.rest.impl.MockServer.ENCUMBRANCE_PATH; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; @@ -24,7 +21,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -39,11 +35,9 @@ import org.folio.rest.acq.model.invoice.InvoiceLine; import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.CompositePoLine; -import org.folio.rest.jaxrs.model.CompositePurchaseOrder; import org.folio.rest.jaxrs.model.FundDistribution; import org.folio.rest.jaxrs.model.PoLine; import org.folio.service.finance.FiscalYearService; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.folio.service.invoice.InvoiceLineService; import org.folio.service.orders.OrderInvoiceRelationService; import org.junit.jupiter.api.BeforeEach; @@ -62,8 +56,6 @@ @ExtendWith(VertxExtension.class) public class EncumbranceServiceTest { - private static final String ORDER_ID = "1ab7ef6a-d1d4-4a4f-90a2-882aed18af14"; - private static final String ORDER_PATH = BASE_MOCK_DATA_PATH + "compositeOrders/" + ORDER_ID + ".json"; public static final String TENANT_ID = "ordertest"; public static final Header X_OKAPI_TENANT = new Header(OKAPI_HEADER_TENANT, TENANT_ID); @@ -75,8 +67,6 @@ public class EncumbranceServiceTest { @Mock private TransactionService transactionService; @Mock - private OrderTransactionSummariesService orderTransactionSummariesService; - @Mock private OrderInvoiceRelationService orderInvoiceRelationService; @Mock private InvoiceLineService invoiceLineService; @@ -96,16 +86,16 @@ public void initMocks(){ } @Test - void testShouldInvokeUpdateTransactionTimesEqualToTransactionQuantity() { + void testShouldInvokeBatchUpdateOnce() { //given - - Transaction encumbrance = getMockAsJson(ENCUMBRANCE_PATH).getJsonArray("transactions").getJsonObject(0).mapTo(Transaction.class); - doReturn(succeededFuture(null)).when(transactionService).updateTransaction(any(), eq(requestContextMock)); - doReturn(succeededFuture(null)).when(orderTransactionSummariesService).updateTransactionSummary(anyString(), anyInt(), eq(requestContextMock)); + Transaction encumbrance = getMockAsJson(ENCUMBRANCE_PATH).getJsonArray("transactions").getJsonObject(0) + .mapTo(Transaction.class); + doReturn(succeededFuture(null)) + .when(transactionService).batchAllOrNothing(anyList(), anyList(), anyList(), anyList(), eq(requestContextMock)); //When encumbranceService.updateEncumbrances(Arrays.asList(encumbrance, encumbrance), requestContextMock); //Then - verify(transactionService, times(1)).updateTransactions(any(), eq(requestContextMock)); + verify(transactionService, times(1)).batchUpdate(any(), eq(requestContextMock)); } @Test @@ -145,25 +135,9 @@ void test() { verify(transactionService, times(1)).getTransactions(anyString(), eq(requestContextMock)); } - @Test - void testShouldUpdateEncumbranceWithNewAmountFromLineAndFundFromLine() { - //Given - - CompositePurchaseOrder order = getMockAsJson(ORDER_PATH).mapTo(CompositePurchaseOrder.class); - CompositePoLine line = order.getCompositePoLines().get(0); - FundDistribution fundDistribution = order.getCompositePoLines().get(0).getFundDistribution().get(0); - Transaction encumbrance = getMockAsJson(ENCUMBRANCE_PATH).getJsonArray("transactions").getJsonObject(0).mapTo(Transaction.class); - //When - encumbranceService.updateEncumbrance(fundDistribution, line, encumbrance); - //Then - assertEquals(BigDecimal.valueOf(line.getCost().getListUnitPrice()), BigDecimal.valueOf(encumbrance.getAmount())); - assertEquals(BigDecimal.valueOf(encumbrance.getAmount()), BigDecimal.valueOf(encumbrance.getEncumbrance().getInitialAmountEncumbered())); - } - @Test void shouldSimplyDeleteWhenDeleteOrderEncumbrances() { //Given - String orderId = UUID.randomUUID().toString(); Transaction encumbrance = new Transaction() .withId(UUID.randomUUID().toString()) @@ -174,24 +148,22 @@ void shouldSimplyDeleteWhenDeleteOrderEncumbrances() { List transactions = new ArrayList<>(); transactions.add(encumbrance); transactions.add(encumbrance2); - doReturn(Future.succeededFuture(transactions)).when(transactionService).getTransactions(anyString(), eq(requestContextMock)); + doReturn(Future.succeededFuture(transactions)) + .when(transactionService).getTransactions(anyString(), eq(requestContextMock)); + doReturn(Future.succeededFuture(null)) + .when(transactionService).batchReleaseAndDelete(anyList(), eq(requestContextMock)); - doReturn(Future.succeededFuture(null)).when(orderTransactionSummariesService).updateTransactionSummary(anyString(), anyInt(), eq(requestContextMock)); - doReturn(Future.succeededFuture(null)).when(transactionService).updateTransactions(any(), eq(requestContextMock)); - doReturn(Future.succeededFuture(null)).when(transactionService).deleteTransactions(any(), eq(requestContextMock)); //When encumbranceService.deleteOrderEncumbrances(orderId, requestContextMock).result(); //Then InOrder inOrder = inOrder(transactionService); - inOrder.verify(transactionService).deleteTransactions(any(), eq(requestContextMock)); - + inOrder.verify(transactionService).batchReleaseAndDelete(anyList(), eq(requestContextMock)); } @Test void shouldSimplyDeleteWhenDeletePoLineEncumbrances() { //Given - String lineId = UUID.randomUUID().toString(); String orderId = UUID.randomUUID().toString(); Transaction encumbrance = new Transaction() @@ -207,18 +179,17 @@ void shouldSimplyDeleteWhenDeletePoLineEncumbrances() { List transactions = new ArrayList<>(); transactions.add(encumbrance); transactions.add(encumbrance2); - doReturn(Future.succeededFuture(transactions)).when(transactionService).getTransactions(anyString(), any()); + doReturn(Future.succeededFuture(transactions)) + .when(transactionService).getTransactions(anyString(), eq(requestContextMock)); + doReturn(Future.succeededFuture(null)) + .when(transactionService).batchReleaseAndDelete(anyList(), eq(requestContextMock)); - doReturn(Future.succeededFuture(null)).when(orderTransactionSummariesService).updateTransactionSummary(any(), anyInt(), eq(requestContextMock)); - doReturn(Future.succeededFuture(null)).when(transactionService).updateTransactions(any(), eq(requestContextMock)); - doReturn(Future.succeededFuture(null)).when(transactionService).deleteTransactions(any(), eq(requestContextMock)); //When encumbranceService.deletePoLineEncumbrances(new PoLine(), requestContextMock).result(); //Then InOrder inOrder = inOrder(transactionService); - inOrder.verify(transactionService).deleteTransactions(any(), eq(requestContextMock)); - + inOrder.verify(transactionService).batchReleaseAndDelete(anyList(), eq(requestContextMock)); } @Test diff --git a/src/test/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategyTest.java b/src/test/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategyTest.java index 5d0aaa355..be3a8c118 100644 --- a/src/test/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategyTest.java +++ b/src/test/java/org/folio/service/finance/transaction/OpenToClosedEncumbranceStrategyTest.java @@ -7,7 +7,6 @@ import static org.folio.TestUtils.getMockAsJson; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; @@ -26,7 +25,6 @@ import org.folio.rest.jaxrs.model.CompositePurchaseOrder; import org.folio.rest.jaxrs.model.CompositePurchaseOrder.WorkflowStatus; import org.folio.rest.jaxrs.model.FundDistribution; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -45,8 +43,6 @@ public class OpenToClosedEncumbranceStrategyTest { @Mock private EncumbranceService encumbranceService; @Mock - private OrderTransactionSummariesService orderTransactionSummariesService; - @Mock EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder; @Mock private RequestContext requestContext; @@ -79,7 +75,6 @@ void testShouldReleaseAndSetOrderStatusToEncumbrances() { .withEncumbrance(encumbrance); List encumbrances = singletonList(transaction); doReturn(succeededFuture(encumbrances)).when(encumbranceService).getEncumbrancesByPoLinesFromCurrentFy(any(), any()); - doReturn(succeededFuture(null)).when(orderTransactionSummariesService).updateTransactionSummary(eq(order.getId()), anyInt(), any()); doReturn(succeededFuture(null)).when(encumbranceService).updateEncumbrances(any(), any()); // When diff --git a/src/test/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategyTest.java b/src/test/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategyTest.java index 5afb98024..a6d9820c2 100644 --- a/src/test/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategyTest.java +++ b/src/test/java/org/folio/service/finance/transaction/OpenToPendingEncumbranceStrategyTest.java @@ -15,7 +15,6 @@ import static org.folio.rest.impl.PurchaseOrdersApiTest.X_OKAPI_TENANT; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; @@ -37,7 +36,6 @@ import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.CompositePoLine; import org.folio.rest.jaxrs.model.CompositePurchaseOrder; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -58,8 +56,6 @@ public class OpenToPendingEncumbranceStrategyTest { @Mock private EncumbranceService encumbranceService; @Mock - private OrderTransactionSummariesService orderTransactionSummariesService; - @Mock private TransactionService transactionService; @Mock EncumbranceRelationsHoldersBuilder encumbranceRelationsHoldersBuilder; @@ -98,7 +94,6 @@ void testShouldSetEncumbrancesToPending() { doReturn(succeededFuture(Collections.singletonList(encumbrance))).when(encumbranceService).getOrderUnreleasedEncumbrances(any(), any()); - doReturn(succeededFuture(null)).when(orderTransactionSummariesService).updateTransactionSummary(eq(order.getId()), anyInt(), any()); doReturn(succeededFuture(null)).when(encumbranceService).updateEncumbrances(any(), any()); List encumbranceRelationsHolders = new ArrayList<>(); diff --git a/src/test/java/org/folio/service/finance/transaction/PendingToOpenEncumbranceStrategyTest.java b/src/test/java/org/folio/service/finance/transaction/PendingToOpenEncumbranceStrategyTest.java index 3474d9227..e6f94b66b 100644 --- a/src/test/java/org/folio/service/finance/transaction/PendingToOpenEncumbranceStrategyTest.java +++ b/src/test/java/org/folio/service/finance/transaction/PendingToOpenEncumbranceStrategyTest.java @@ -8,7 +8,6 @@ import static org.folio.TestUtils.getMockAsJson; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; - import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; @@ -30,7 +29,7 @@ import org.folio.rest.acq.model.finance.FiscalYear; import org.folio.rest.acq.model.finance.Fund; import org.folio.rest.acq.model.finance.Ledger; - import org.folio.rest.acq.model.finance.OrderTransactionSummary; + import org.folio.rest.acq.model.finance.Metadata; import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.CompositePoLine; @@ -44,7 +43,6 @@ import org.folio.service.finance.LedgerService; import org.folio.service.finance.budget.BudgetRestrictionService; import org.folio.service.finance.budget.BudgetService; - import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.folio.service.invoice.InvoiceLineService; import org.folio.service.invoice.POLInvoiceLineRelationService; import org.folio.service.orders.OrderInvoiceRelationService; @@ -74,8 +72,6 @@ public class PendingToOpenEncumbranceStrategyTest { @Mock private TransactionService transactionService; @Mock - private OrderTransactionSummariesService orderTransactionSummariesService; - @Mock private OrderInvoiceRelationService orderInvoiceRelationService; @Mock private FundService fundService; @@ -100,7 +96,7 @@ public class PendingToOpenEncumbranceStrategyTest { @BeforeEach void init() { - EncumbranceService encumbranceService = new EncumbranceService(transactionService, orderTransactionSummariesService, + EncumbranceService encumbranceService = new EncumbranceService(transactionService, invoiceLineService, orderInvoiceRelationService, fiscalYearService); FundsDistributionService fundsDistributionService = new FundsDistributionService(); @@ -153,7 +149,8 @@ void testUnreleaseBeforeAndReleaseAfterWhenUpdatingAReleasedEncumbrance(VertxTes .withAmount(0d) .withId(fd1.getEncumbrance()) .withFromFundId(fd1.getFundId()) - .withEncumbrance(encumbrance); + .withEncumbrance(encumbrance) + .withMetadata(new Metadata()); Transaction unreleased = JsonObject.mapFrom(released).mapTo(Transaction.class); unreleased.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED); @@ -189,22 +186,13 @@ void testUnreleaseBeforeAndReleaseAfterWhenUpdatingAReleasedEncumbrance(VertxTes .doThrow(new RuntimeException("Too many invocations of getTransactionsByIds()")) .when(transactionService).getTransactionsByIds(argThat(list -> list.size() == 1), eq(requestContext)); doReturn(succeededFuture(null)) - .when(transactionService).updateTransactions(anyList(), eq(requestContext)); - doAnswer(i -> succeededFuture(i.getArguments()[0])) - .when(transactionService).createTransaction(any(Transaction.class), eq(requestContext)); - OrderTransactionSummary orderTransactionSummary = new OrderTransactionSummary() - .withId(UUID.randomUUID().toString()) - .withNumTransactions(123); - doReturn(succeededFuture(orderTransactionSummary)) - .when(orderTransactionSummariesService).getTransactionSummary(anyString(), eq(requestContext)); + .when(transactionService).batchAllOrNothing(any(), any(), any(), any(), eq(requestContext)); doCallRealMethod() - .when(orderTransactionSummariesService).updateTransactionSummary(anyString(), anyInt(), eq(requestContext)); + .when(transactionService).batchUpdate(anyList(), eq(requestContext)); doCallRealMethod() - .when(orderTransactionSummariesService).updateOrCreateTransactionSummary(anyString(), anyInt(), eq(requestContext)); + .when(transactionService).batchRelease(anyList(), eq(requestContext)); doCallRealMethod() - .when(orderTransactionSummariesService).createOrUpdateOrderTransactionSummary(any(), eq(requestContext)); - doReturn(succeededFuture(null)) - .when(orderTransactionSummariesService).updateTransactionSummary(any(), eq(requestContext)); + .when(transactionService).batchUnrelease(anyList(), eq(requestContext)); getDefaultRounding(); // When @@ -214,7 +202,7 @@ void testUnreleaseBeforeAndReleaseAfterWhenUpdatingAReleasedEncumbrance(VertxTes vertxTestContext.assertComplete(future) .onSuccess(result -> vertxTestContext.verify(() -> { verify(transactionService, times(3)) - .updateTransactions(transactionListCaptor.capture(), eq(requestContext)); + .batchAllOrNothing(any(), transactionListCaptor.capture(), any(), any(), eq(requestContext)); List> transactionLists = transactionListCaptor.getAllValues(); assertEquals(3, transactionLists.size()); assertEquals(1, transactionLists.get(0).size()); diff --git a/src/test/java/org/folio/service/finance/transaction/TransactionServiceTest.java b/src/test/java/org/folio/service/finance/transaction/TransactionServiceTest.java index c2844619c..b83cceb3f 100644 --- a/src/test/java/org/folio/service/finance/transaction/TransactionServiceTest.java +++ b/src/test/java/org/folio/service/finance/transaction/TransactionServiceTest.java @@ -4,15 +4,15 @@ import static org.folio.TestUtils.getMockAsJson; import static org.folio.rest.impl.MockServer.ENCUMBRANCE_PATH; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import org.folio.rest.acq.model.finance.Batch; import org.folio.rest.acq.model.finance.Transaction; import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; -import org.folio.rest.core.models.RequestEntry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -23,6 +23,8 @@ import io.vertx.junit5.VertxExtension; +import java.util.List; + @ExtendWith(VertxExtension.class) public class TransactionServiceTest { @@ -39,22 +41,23 @@ public void initMocks(){ } @Test - void testShouldInvokeUpdateTransaction() throws Exception { - //given - Transaction encumbrance = getMockAsJson(ENCUMBRANCE_PATH).getJsonArray("transactions").getJsonObject(0).mapTo(Transaction.class); - doReturn(succeededFuture()).when(restClient).put(any(RequestEntry.class), eq(encumbrance), eq(requestContext)); + void testShouldInvokeUpdateTransaction() { + //Given + Transaction encumbrance = getMockAsJson(ENCUMBRANCE_PATH).getJsonArray("transactions").getJsonObject(0) + .mapTo(Transaction.class); + Batch batch = new Batch() + .withTransactionsToUpdate(List.of(encumbrance)); + doReturn(succeededFuture()) + .when(restClient).postEmptyResponse(anyString(), eq(batch), eq(requestContext)); + //When - transactionService.updateTransaction(encumbrance, requestContext).result(); - //Then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(RequestEntry.class); - verify(restClient).put(argumentCaptor.capture(), eq(encumbrance), eq(requestContext)); - RequestEntry requestEntry = argumentCaptor.getValue(); + transactionService.batchUpdate(List.of(encumbrance), requestContext).result(); - assertEquals(encumbrance.getId(), requestEntry.getPathParams().get("id")); - assertEquals("/finance/encumbrances/{id}", requestEntry.getBaseEndpoint()); + //Then + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + verify(restClient).postEmptyResponse(argumentCaptor.capture(), eq(batch), eq(requestContext)); + String endPoint = argumentCaptor.getValue(); + assertEquals("/finance/transactions/batch-all-or-nothing", endPoint); } - - - } diff --git a/src/test/java/org/folio/service/finance/transaction/TransactionSummariesServiceTest.java b/src/test/java/org/folio/service/finance/transaction/TransactionSummariesServiceTest.java deleted file mode 100644 index 49f7d0aa3..000000000 --- a/src/test/java/org/folio/service/finance/transaction/TransactionSummariesServiceTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.folio.service.finance.transaction; - -import static io.vertx.core.Future.succeededFuture; -import static org.folio.TestUtils.getMockAsJson; -import static org.folio.helper.PurchaseOrderHelperTest.ORDER_PATH; -import static org.folio.rest.impl.MockServer.ENCUMBRANCE_PATH; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.UUID; - -import io.vertx.core.Future; -import io.vertx.core.json.JsonObject; -import io.vertx.junit5.VertxExtension; -import org.folio.rest.acq.model.finance.OrderTransactionSummary; -import org.folio.rest.acq.model.finance.Transaction; -import org.folio.rest.core.RestClient; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.core.models.RequestEntry; -import org.folio.rest.jaxrs.model.CompositePoLine; -import org.folio.rest.jaxrs.model.CompositePurchaseOrder; -import org.folio.rest.jaxrs.model.FundDistribution; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@ExtendWith(VertxExtension.class) -public class TransactionSummariesServiceTest { - - @InjectMocks - private OrderTransactionSummariesService orderTransactionSummariesService; - - @Mock - private RestClient restClient; - - @Mock - private RequestContext requestContext; - - @BeforeEach - public void initMocks() { - MockitoAnnotations.openMocks(this); - } - - @Test - void testShouldNotUpdateTransactionsSummariesWhenNoEncumbrances() { - // When - orderTransactionSummariesService.updateTransactionSummary(UUID.randomUUID() - .toString(), 0, requestContext); - // Then - verify(restClient, never()).put(anyString(), any(), any()); - } - - @Test - void testShouldTransactionsCreatedForEncumbrances() { - // Given - CompositePurchaseOrder order = getMockAsJson(ORDER_PATH).mapTo(CompositePurchaseOrder.class); - CompositePoLine line = order.getCompositePoLines() - .get(0); - Transaction encumbrance = getMockAsJson(ENCUMBRANCE_PATH).getJsonArray("transactions") - .getJsonObject(0) - .mapTo(Transaction.class); - FundDistribution fundDistribution = order.getCompositePoLines() - .get(0) - .getFundDistribution() - .get(0); - // When - orderTransactionSummariesService.updateTransactionSummary(order.getId(), 1, requestContext); - // Then - assertNull(orderTransactionSummariesService.getTransactionSummary(order.getId(), requestContext)); - } - - @Test - void testShouldCreateTransactionSummaryInStorageTransactions() { - // Given - String uuid = UUID.randomUUID().toString(); - JsonObject response = new JsonObject().put("id", uuid); - when(restClient.post(any(RequestEntry.class), any(), any(), any(RequestContext.class))) - .thenReturn(succeededFuture(response)); - OrderTransactionSummary expectedSummary = new OrderTransactionSummary().withId(uuid).withNumTransactions(2); - // When - Future result = orderTransactionSummariesService.createTransactionSummary(expectedSummary, requestContext); - // Then - verify(restClient).post(any(RequestEntry.class), any(), any(), any(RequestContext.class)); - JsonObject res = JsonObject.mapFrom(result.result()); - String resultId = res.getString("id"); - assertEquals(uuid, resultId); - } -} - diff --git a/src/test/java/org/folio/service/orders/OrderReEncumberServiceTest.java b/src/test/java/org/folio/service/orders/OrderReEncumberServiceTest.java index 076ab228e..4b9d770a9 100644 --- a/src/test/java/org/folio/service/orders/OrderReEncumberServiceTest.java +++ b/src/test/java/org/folio/service/orders/OrderReEncumberServiceTest.java @@ -19,16 +19,13 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -63,13 +60,10 @@ import org.folio.service.finance.rollover.LedgerRolloverProgressService; import org.folio.service.finance.rollover.LedgerRolloverService; import org.folio.service.finance.transaction.TransactionService; -import org.folio.service.finance.transaction.summary.OrderTransactionSummariesService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.AdditionalMatchers; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -104,16 +98,11 @@ public class OrderReEncumberServiceTest { @Mock private TransactionService transactionService; @Mock - private OrderTransactionSummariesService orderTransactionSummariesService; - @Mock private ReEncumbranceHoldersBuilder spyReEncumbranceHoldersBuilder; @Mock private RequestContext requestContext; - @Captor - ArgumentCaptor> argumentCaptorForList; - private LedgerFiscalYearRolloverProgress notStarted; private LedgerFiscalYearRolloverProgress inProgress; private LedgerFiscalYearRolloverProgress success; @@ -470,8 +459,8 @@ void shouldFailReEncumberHoldersWithEmptyEncumbranceRollover(VertxTestContext ve List toTransactionList = Collections.emptyList(); when(transactionService.getTransactions(anyString(), eq(requestContext))) .thenReturn(succeededFuture(toTransactionList)); - when(orderTransactionSummariesService.updateTransactionSummary(eq(orderId), anyInt(), eq(requestContext))).thenReturn(succeededFuture(null)); - when(transactionService.createTransaction(any(), eq(requestContext))).thenReturn(succeededFuture(new Transaction())); + when(transactionService.batchCreate(anyList(), eq(requestContext))) + .thenReturn(succeededFuture()); Future future = orderReEncumberService.reEncumber(orderId, requestContext); @@ -639,8 +628,8 @@ void shouldVerifyFYROAdjustmentAndFundDistributionValuesWhenMixedFunds(VertxTest when(exchangeRateProviderResolver.resolve(conversionFyToPoLineQuery, requestContext)).thenReturn(exchangeRateProvider); when(transactionService.getTransactions(anyString(), eq(requestContext))) .thenReturn(succeededFuture(toTransactionList)); - when(orderTransactionSummariesService.updateTransactionSummary(eq(orderId), anyInt(), eq(requestContext))).thenReturn(succeededFuture(null)); - when(transactionService.createTransaction(any(), eq(requestContext))).thenReturn(succeededFuture(new Transaction())); + when(transactionService.batchCreate(anyList(), eq(requestContext))) + .thenReturn(succeededFuture()); //When Future future = orderReEncumberService.reEncumber(UUID.randomUUID().toString(), requestContext); diff --git a/src/test/java/org/folio/service/orders/OrderRolloverServiceTest.java b/src/test/java/org/folio/service/orders/OrderRolloverServiceTest.java index 7045b37c3..eb7a15e5f 100644 --- a/src/test/java/org/folio/service/orders/OrderRolloverServiceTest.java +++ b/src/test/java/org/folio/service/orders/OrderRolloverServiceTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.when; import java.math.BigDecimal; -import java.math.RoundingMode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -626,14 +625,14 @@ void shouldRemoveEncumbranceLinksAndEncumbrancesIfNeededForClosedOrders(VertxTes List encumbrances = singletonList(transaction); doReturn(succeededFuture(encumbrances)).when(transactionService).getTransactions(anyString(), any()); - doReturn(succeededFuture(null)).when(transactionService).deleteTransactions(anyList(), any()); + doReturn(succeededFuture(null)).when(transactionService).batchDelete(anyList(), any()); Future future = orderRolloverService.startRollover(ledgerFiscalYearRollover, progress, requestContext); sleep(3000); vertxTestContext.assertComplete(future) .onSuccess(result -> { - verify(transactionService, times(1)).deleteTransactions( - argThat(transactions -> transactions.size() == 1 && currEncumbrId.equals(transactions.get(0).getId())), any()); + verify(transactionService, times(1)).batchDelete( + argThat(transactionIds -> transactionIds.size() == 1 && currEncumbrId.equals(transactionIds.get(0))), any()); verify(purchaseOrderLineService).saveOrderLines(argumentCaptor.capture(), any(RequestContext.class)); assertThat(argumentCaptor.getAllValues().get(0).get(0).getFundDistribution().get(0).getEncumbrance(), equalTo(null));