> entry) {
- Budget budget = entry.getKey();
- CurrencyUnit currency = Monetary.getCurrency(entry.getValue()
- .get(0)
- .getCurrency());
- entry.getValue()
- .forEach(txn -> {
- budget.setExpenditures(MoneyUtils.subtractMoney(budget.getExpenditures(), txn.getAmount(), currency));
- budget.setAwaitingPayment(MoneyUtils.sumMoney(budget.getAwaitingPayment(), txn.getAmount(), currency));
- budgetService.updateBudgetMetadata(budget, txn);
- budgetService.clearReadOnlyFields(budget);
- });
- }
-
- /**
- *
- * Encumbrances are recalculated with the credit transaction as below:
- * - expended decreases by credit transaction amount (min 0)
- *
- */
- private Map applyCredits(List tempTxns, Map encumbrancesMap) {
-
- List tempCredits = tempTxns.stream()
- .filter(isCreditTransaction.and(hasEncumbrance))
- .toList();
-
- if (tempCredits.isEmpty()) {
- return encumbrancesMap;
- }
- CurrencyUnit currency = Monetary.getCurrency(tempCredits.get(0)
- .getCurrency());
- tempCredits.forEach(creditTxn -> {
- Transaction encumbranceTxn = encumbrancesMap.get(creditTxn.getPaymentEncumbranceId());
-
- double newExpended = MoneyUtils.subtractMoneyNonNegative(encumbranceTxn.getEncumbrance()
- .getAmountExpended(), creditTxn.getAmount(), currency);
- double newAwaitingPayment = MoneyUtils.sumMoney(encumbranceTxn.getEncumbrance()
- .getAmountAwaitingPayment(), creditTxn.getAmount(), currency);
- encumbranceTxn.getEncumbrance()
- .withAmountExpended(newExpended)
- .withAmountAwaitingPayment(newAwaitingPayment);
-
- });
-
- return encumbrancesMap;
- }
-
- /**
- *
- * Encumbrances are recalculated with the payment transaction as below:
- * - expended increases by payment transaction amount
- *
- */
- private Map applyPayments(List tempTxns, Map encumbrancesMap) {
- List tempPayments = tempTxns.stream()
- .filter(isPaymentTransaction.and(hasEncumbrance))
- .toList();
- if (tempPayments.isEmpty()) {
- return encumbrancesMap;
- }
-
- CurrencyUnit currency = Monetary.getCurrency(tempPayments.get(0)
- .getCurrency());
- tempPayments.forEach(pymtTxn -> {
- Transaction encumbranceTxn = encumbrancesMap.get(pymtTxn.getPaymentEncumbranceId());
- double newExpended = MoneyUtils.sumMoney(encumbranceTxn.getEncumbrance()
- .getAmountExpended(), pymtTxn.getAmount(), currency);
- double newAwaitingPayment = MoneyUtils.subtractMoney(encumbranceTxn.getEncumbrance()
- .getAmountAwaitingPayment(), pymtTxn.getAmount(), currency);
-
- encumbranceTxn.getEncumbrance()
- .withAmountExpended(newExpended)
- .withAmountAwaitingPayment(newAwaitingPayment);
-
- });
-
- return encumbrancesMap;
- }
-
- private Future> getAllEncumbrances(String summaryId, DBConn conn) {
- logger.debug("getAllEncumbrances:: Trying to get all encumbrances by summary id {}", summaryId);
- String sql = buildGetPermanentEncumbrancesQuery(conn.getTenantId());
- return conn.execute(sql, Tuple.of(UUID.fromString(summaryId)))
- .map(rowSet -> {
- List encumbrances = new ArrayList<>();
- rowSet.spliterator().forEachRemaining(row -> encumbrances.add(row.get(JsonObject.class, 0).mapTo(Transaction.class)));
- return encumbrances;
- })
- .onSuccess(encumbrances -> logger.info("Successfully retrieved {} encumbrances by summary id {}",
- encumbrances.size(), summaryId))
- .onFailure(e -> logger.error("getAllEncumbrances:: Getting all encumbrances by summary id {} failed", summaryId, e));
- }
-
- private String buildGetPermanentEncumbrancesQuery(String tenantId) {
- return String.format(SELECT_PERMANENT_TRANSACTIONS, getFullTableName(tenantId, TRANSACTIONS_TABLE),
- getFullTableName(tenantId, TEMPORARY_INVOICE_TRANSACTIONS));
- }
-
- private String getSelectBudgetsQueryForUpdate(String tenantId){
- String budgetTableName = getFullTableName(tenantId, BUDGET_TABLE);
- String transactionTableName = getFullTableName(tenantId, TEMPORARY_INVOICE_TRANSACTIONS);
- return String.format(SELECT_BUDGETS_BY_INVOICE_ID_FOR_UPDATE, budgetTableName, budgetTableName, transactionTableName);
- }
-
- public Transaction.TransactionType getStrategyName() {
- return PAYMENT;
- }
-
-
- public String getSummaryId(Transaction transaction) {
- return transaction.getSourceInvoiceId();
- }
-}
diff --git a/src/main/java/org/folio/service/transactions/PendingPaymentService.java b/src/main/java/org/folio/service/transactions/PendingPaymentService.java
deleted file mode 100644
index da1eea60..00000000
--- a/src/main/java/org/folio/service/transactions/PendingPaymentService.java
+++ /dev/null
@@ -1,353 +0,0 @@
-package org.folio.service.transactions;
-
-import static io.vertx.core.Future.succeededFuture;
-import static java.lang.Boolean.TRUE;
-import static java.util.function.Function.identity;
-import static java.util.stream.Collectors.groupingBy;
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.Collectors.toMap;
-import static javax.money.Monetary.getDefaultRounding;
-import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
-import static org.folio.dao.transactions.TemporaryInvoiceTransactionDAO.TEMPORARY_INVOICE_TRANSACTIONS;
-import static org.folio.rest.impl.BudgetAPI.BUDGET_TABLE;
-import static org.folio.rest.jaxrs.model.Transaction.TransactionType.PENDING_PAYMENT;
-import static org.folio.rest.persist.HelperUtils.getFullTableName;
-import static org.folio.rest.util.ErrorCodes.OUTDATED_FUND_ID_IN_ENCUMBRANCE;
-import static org.folio.utils.MoneyUtils.subtractMoney;
-import static org.folio.utils.MoneyUtils.sumMoney;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-import javax.money.CurrencyUnit;
-import javax.money.Monetary;
-import javax.money.MonetaryAmount;
-import javax.ws.rs.core.Response;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.folio.rest.exception.HttpException;
-import org.folio.dao.transactions.TransactionDAO;
-import org.folio.rest.jaxrs.model.Budget;
-import org.folio.rest.jaxrs.model.Encumbrance;
-import org.folio.rest.jaxrs.model.Error;
-import org.folio.rest.jaxrs.model.Parameter;
-import org.folio.rest.jaxrs.model.Transaction;
-import org.folio.rest.persist.DBConn;
-import org.folio.service.budget.BudgetService;
-import org.folio.service.transactions.cancel.CancelTransactionService;
-import org.javamoney.moneta.Money;
-
-import io.vertx.core.Future;
-import io.vertx.core.json.JsonObject;
-import io.vertx.sqlclient.Tuple;
-import org.javamoney.moneta.function.MonetaryFunctions;
-
-public class PendingPaymentService extends AbstractTransactionService implements TransactionManagingStrategy {
-
- private static final Logger logger = LogManager.getLogger(PendingPaymentService.class);
-
- public static final String SELECT_BUDGETS_BY_INVOICE_ID_FOR_UPDATE =
- "SELECT b.jsonb FROM %s b INNER JOIN (SELECT DISTINCT budgets.id FROM %s budgets INNER JOIN %s transactions "
- + "ON (budgets.fundId = transactions.fromFundId AND transactions.fiscalYearId = budgets.fiscalYearId) "
- + "WHERE transactions.sourceInvoiceId = $1 AND transactions.jsonb ->> 'transactionType' = 'Pending payment') "
- + "sub ON sub.id = b.id "
- + "FOR UPDATE OF b";
-
- private final AllOrNothingTransactionService allOrNothingTransactionService;
- private final BudgetService budgetService;
- private final CancelTransactionService cancelTransactionService;
-
- public PendingPaymentService(AllOrNothingTransactionService allOrNothingTransactionService,
- TransactionDAO transactionDAO,
- BudgetService budgetService,
- CancelTransactionService cancelTransactionService) {
- super(transactionDAO);
- this.allOrNothingTransactionService = allOrNothingTransactionService;
- this.budgetService = budgetService;
- this.cancelTransactionService = cancelTransactionService;
- }
-
- @Override
- public Future createTransaction(Transaction transaction, DBConn conn) {
- return allOrNothingTransactionService.createTransaction(transaction, conn, this::createTransactions);
- }
-
- @Override
- public Future updateTransaction(Transaction transaction, DBConn conn) {
- return allOrNothingTransactionService.updateTransaction(transaction, conn, this::cancelAndUpdateTransactions);
- }
-
- @Override
- public Transaction.TransactionType getStrategyName() {
- return PENDING_PAYMENT;
- }
-
- public Future createTransactions(List transactions, DBConn conn) {
- return processPendingPayments(transactions, conn)
- .compose(aVoid -> transactionDAO.saveTransactionsToPermanentTable(transactions.get(0).getSourceInvoiceId(), conn))
- .mapEmpty();
- }
-
- public Future cancelAndUpdateTransactions(List tmpTransactions, DBConn conn) {
- return getTransactions(tmpTransactions, conn)
- .compose(existingTransactions -> {
- List idsToCancel = tmpTransactions.stream()
- .filter(tr -> TRUE.equals(tr.getInvoiceCancelled()))
- .map(Transaction::getId)
- .filter(id -> existingTransactions.stream().anyMatch(
- tr -> tr.getId().equals(id) && !TRUE.equals(tr.getInvoiceCancelled())))
- .toList();
- List tmpTransactionsToCancel = tmpTransactions.stream()
- .filter(tr -> idsToCancel.contains(tr.getId()))
- .collect(toList());
- List tmpTransactionsToUpdate = tmpTransactions.stream()
- .filter(tr -> !idsToCancel.contains(tr.getId()))
- .collect(toList());
- List existingTransactionsToUpdate = existingTransactions.stream()
- .filter(tr -> !idsToCancel.contains(tr.getId()))
- .collect(toList());
- return cancelTransactions(tmpTransactionsToCancel, conn)
- .compose(v -> updateTransactions(tmpTransactionsToUpdate, existingTransactionsToUpdate, conn));
- });
- }
-
- private Future cancelTransactions(List tmpTransactions, DBConn conn) {
- if (tmpTransactions.isEmpty())
- return succeededFuture();
- return cancelTransactionService.cancelTransactions(tmpTransactions, conn)
- .map(voidedTransactions -> null);
- }
-
- private Future updateTransactions(List tmpTransactions, List existingTransactions,
- DBConn conn) {
- if (tmpTransactions.isEmpty())
- return succeededFuture();
- List transactions = createDifferenceTransactions(tmpTransactions, existingTransactions);
- return processPendingPayments(transactions, conn)
- .map(processedTransactions -> null)
- .compose(v -> transactionDAO.updatePermanentTransactions(tmpTransactions, conn));
- }
-
- private Future> processPendingPayments(List transactions, DBConn conn) {
- List linkedToEncumbrance = transactions.stream()
- .filter(transaction -> Objects.nonNull(transaction.getAwaitingPayment()) && Objects.nonNull(transaction.getAwaitingPayment().getEncumbranceId()))
- .collect(Collectors.toList());
- List notLinkedToEncumbrance = transactions.stream()
- .filter(transaction -> Objects.isNull(transaction.getAwaitingPayment()) || Objects.isNull(transaction.getAwaitingPayment().getEncumbranceId()))
- .collect(Collectors.toList());
-
- String summaryId = getSummaryId(transactions.get(0));
-
- return budgetService.getBudgets(getSelectBudgetsQueryForUpdate(conn.getTenantId()), Tuple.of(UUID.fromString(summaryId)), conn)
- .compose(oldBudgets -> processLinkedPendingPayments(linkedToEncumbrance, oldBudgets, conn)
- .map(budgets -> processNotLinkedPendingPayments(notLinkedToEncumbrance, budgets))
- .compose(newBudgets -> budgetService.updateBatchBudgets(newBudgets, conn)))
- .map(transactions);
- }
-
- private List createDifferenceTransactions(List tmpTransactions, List transactionsFromDB) {
- Map amountIdMap = tmpTransactions.stream().collect(toMap(Transaction::getId, Transaction::getAmount));
- return transactionsFromDB.stream()
- .map(transaction -> createDifferenceTransaction(transaction, amountIdMap.getOrDefault(transaction.getId(), 0d)))
- .collect(Collectors.toList());
- }
-
- private Transaction createDifferenceTransaction(Transaction transaction, double newAmount) {
- Transaction transactionDifference = JsonObject.mapFrom(transaction).mapTo(Transaction.class);
- CurrencyUnit currency = Monetary.getCurrency(transaction.getCurrency());
- double amountDifference = subtractMoney(newAmount, transaction.getAmount(), currency);
- return transactionDifference.withAmount(amountDifference);
- }
-
-
- private Future> getTransactions(List tmpTransactions, DBConn conn) {
-
- List ids = tmpTransactions.stream()
- .map(Transaction::getId)
- .collect(toList());
-
- return transactionDAO.getTransactions(ids, conn);
- }
-
- private List processNotLinkedPendingPayments(List pendingPayments, List oldBudgets) {
- if (isNotEmpty(pendingPayments)) {
- return updateBudgetsTotalsWithNotLinkedPendingPayments(pendingPayments, oldBudgets);
- }
- return oldBudgets;
- }
-
- private List updateBudgetsTotalsWithNotLinkedPendingPayments(List tempTransactions, List budgets) {
- Map> tempGrouped = groupTransactionsByBudget(tempTransactions, budgets);
- return tempGrouped.entrySet().stream()
- .map(this::updateBudgetTotalsWithNotLinkedPendingPayments)
- .collect(toList());
- }
-
- private Map