Search in sources :

Example 1 with EncumbranceRelationsHolder

use of org.folio.models.EncumbranceRelationsHolder in project mod-orders by folio-org.

the class EncumbranceRelationsHoldersBuilder method mapRestrictEncumbranceToHolders.

private List<EncumbranceRelationsHolder> mapRestrictEncumbranceToHolders(List<Ledger> ledgers, List<EncumbranceRelationsHolder> encumbranceHolders) {
    Map<String, Ledger> idLedgerMap = ledgers.stream().collect(toMap(Ledger::getId, Function.identity()));
    encumbranceHolders.stream().filter(holder -> Objects.nonNull(holder.getLedgerId())).forEach(holder -> {
        Ledger ledger = idLedgerMap.get(holder.getLedgerId());
        holder.withRestrictEncumbrances(Optional.ofNullable(ledger).map(Ledger::getRestrictEncumbrance).orElse(false));
    });
    return encumbranceHolders;
}
Also used : Cost(org.folio.rest.jaxrs.model.Cost) CurrencyConversion(javax.money.convert.CurrencyConversion) BudgetService(org.folio.service.finance.budget.BudgetService) Collectors.groupingBy(java.util.stream.Collectors.groupingBy) CompletableFuture(java.util.concurrent.CompletableFuture) FolioVertxCompletableFuture(org.folio.completablefuture.FolioVertxCompletableFuture) Transaction(org.folio.rest.acq.model.finance.Transaction) Function(java.util.function.Function) Collectors.toMap(java.util.stream.Collectors.toMap) CompositePurchaseOrder(org.folio.rest.jaxrs.model.CompositePurchaseOrder) Collectors.mapping(java.util.stream.Collectors.mapping) Map(java.util.Map) RequestContext(org.folio.rest.core.models.RequestContext) Encumbrance(org.folio.rest.acq.model.finance.Encumbrance) FundService(org.folio.service.finance.FundService) Budget(org.folio.rest.acq.model.finance.Budget) Ongoing(org.folio.rest.jaxrs.model.Ongoing) ExchangeRateProviderResolver(org.folio.service.exchange.ExchangeRateProviderResolver) ConversionQuery(javax.money.convert.ConversionQuery) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder) Ledger(org.folio.rest.acq.model.finance.Ledger) HelperUtils.getConversionQuery(org.folio.orders.utils.HelperUtils.getConversionQuery) FiscalYearService(org.folio.service.finance.FiscalYearService) Fund(org.folio.rest.acq.model.finance.Fund) FundDistribution(org.folio.rest.jaxrs.model.FundDistribution) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Collectors.toList(java.util.stream.Collectors.toList) List(java.util.List) LedgerService(org.folio.service.finance.LedgerService) ExchangeRateProvider(javax.money.convert.ExchangeRateProvider) CompositePoLine(org.folio.rest.jaxrs.model.CompositePoLine) Tags(org.folio.rest.acq.model.finance.Tags) Optional(java.util.Optional) Ledger(org.folio.rest.acq.model.finance.Ledger)

Example 2 with EncumbranceRelationsHolder

use of org.folio.models.EncumbranceRelationsHolder in project mod-orders by folio-org.

the class EncumbranceRelationsHoldersBuilder method withConversion.

public CompletableFuture<List<EncumbranceRelationsHolder>> withConversion(List<EncumbranceRelationsHolder> encumbranceHolders, RequestContext requestContext) {
    return encumbranceHolders.stream().map(EncumbranceRelationsHolder::getCurrency).filter(Objects::nonNull).findFirst().map(transactionCurrency -> FolioVertxCompletableFuture.supplyBlockingAsync(requestContext.getContext(), () -> {
        Map<String, List<EncumbranceRelationsHolder>> currencyHolderMap = encumbranceHolders.stream().filter(holder -> Objects.nonNull(holder.getPoLine())).collect(groupingBy(holder -> holder.getPoLine().getCost().getCurrency()));
        currencyHolderMap.forEach((poLineCurrency, encumbranceRelationsHolders) -> {
            Double exchangeRate = encumbranceRelationsHolders.stream().map(EncumbranceRelationsHolder::getPoLine).map(CompositePoLine::getCost).map(Cost::getExchangeRate).filter(Objects::nonNull).findFirst().orElse(null);
            ConversionQuery conversionQuery = getConversionQuery(exchangeRate, poLineCurrency, transactionCurrency);
            ExchangeRateProvider exchangeRateProvider = exchangeRateProviderResolver.resolve(conversionQuery, requestContext);
            CurrencyConversion conversion = exchangeRateProvider.getCurrencyConversion(conversionQuery);
            encumbranceRelationsHolders.forEach(holder -> holder.withPoLineToFyConversion(conversion));
        });
        return encumbranceHolders;
    })).orElseGet(() -> CompletableFuture.completedFuture(encumbranceHolders));
}
Also used : Cost(org.folio.rest.jaxrs.model.Cost) CurrencyConversion(javax.money.convert.CurrencyConversion) BudgetService(org.folio.service.finance.budget.BudgetService) Collectors.groupingBy(java.util.stream.Collectors.groupingBy) CompletableFuture(java.util.concurrent.CompletableFuture) FolioVertxCompletableFuture(org.folio.completablefuture.FolioVertxCompletableFuture) Transaction(org.folio.rest.acq.model.finance.Transaction) Function(java.util.function.Function) Collectors.toMap(java.util.stream.Collectors.toMap) CompositePurchaseOrder(org.folio.rest.jaxrs.model.CompositePurchaseOrder) Collectors.mapping(java.util.stream.Collectors.mapping) Map(java.util.Map) RequestContext(org.folio.rest.core.models.RequestContext) Encumbrance(org.folio.rest.acq.model.finance.Encumbrance) FundService(org.folio.service.finance.FundService) Budget(org.folio.rest.acq.model.finance.Budget) Ongoing(org.folio.rest.jaxrs.model.Ongoing) ExchangeRateProviderResolver(org.folio.service.exchange.ExchangeRateProviderResolver) ConversionQuery(javax.money.convert.ConversionQuery) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder) Ledger(org.folio.rest.acq.model.finance.Ledger) HelperUtils.getConversionQuery(org.folio.orders.utils.HelperUtils.getConversionQuery) FiscalYearService(org.folio.service.finance.FiscalYearService) Fund(org.folio.rest.acq.model.finance.Fund) FundDistribution(org.folio.rest.jaxrs.model.FundDistribution) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Collectors.toList(java.util.stream.Collectors.toList) List(java.util.List) LedgerService(org.folio.service.finance.LedgerService) ExchangeRateProvider(javax.money.convert.ExchangeRateProvider) CompositePoLine(org.folio.rest.jaxrs.model.CompositePoLine) Tags(org.folio.rest.acq.model.finance.Tags) Optional(java.util.Optional) ConversionQuery(javax.money.convert.ConversionQuery) HelperUtils.getConversionQuery(org.folio.orders.utils.HelperUtils.getConversionQuery) ExchangeRateProvider(javax.money.convert.ExchangeRateProvider) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder) Objects(java.util.Objects) CompositePoLine(org.folio.rest.jaxrs.model.CompositePoLine) CurrencyConversion(javax.money.convert.CurrencyConversion) Collectors.toList(java.util.stream.Collectors.toList) List(java.util.List)

Example 3 with EncumbranceRelationsHolder

use of org.folio.models.EncumbranceRelationsHolder in project mod-orders by folio-org.

the class EncumbranceService method createEncumbrances.

public CompletableFuture<Void> createEncumbrances(List<EncumbranceRelationsHolder> relationsHolders, RequestContext requestContext) {
    List<CompletableFuture<Void>> futureList = new ArrayList<>();
    CompletableFuture<Void> future = completedFuture(null);
    for (EncumbranceRelationsHolder holder : relationsHolders) {
        future = future.thenCompose(v -> transactionService.createTransaction(holder.getNewEncumbrance(), requestContext).thenAccept(transaction -> holder.getFundDistribution().setEncumbrance(transaction.getId())).exceptionally(fail -> {
            checkCustomTransactionError(fail);
            throw new CompletionException(fail);
        }));
        futureList.add(future);
    }
    return FolioVertxCompletableFuture.allOf(requestContext.getContext(), futureList.toArray(new CompletableFuture[0]));
}
Also used : OrderInvoiceRelationService(org.folio.service.orders.OrderInvoiceRelationService) FUND_CANNOT_BE_PAID(org.folio.rest.core.exceptions.ErrorCodes.FUND_CANNOT_BE_PAID) InvoiceLineService(org.folio.service.invoice.InvoiceLineService) CompletableFuture.completedFuture(java.util.concurrent.CompletableFuture.completedFuture) HttpException(org.folio.rest.core.exceptions.HttpException) FolioVertxCompletableFuture(org.folio.completablefuture.FolioVertxCompletableFuture) CompletableFuture(java.util.concurrent.CompletableFuture) HelperUtils.collectResultsOnSuccess(org.folio.orders.utils.HelperUtils.collectResultsOnSuccess) PoLine(org.folio.rest.jaxrs.model.PoLine) Transaction(org.folio.rest.acq.model.finance.Transaction) TransactionCollection(org.folio.rest.acq.model.finance.TransactionCollection) CollectionUtils(org.apache.commons.collections4.CollectionUtils) Objects.requireNonNullElse(java.util.Objects.requireNonNullElse) ArrayList(java.util.ArrayList) EncumbrancesProcessingHolder(org.folio.models.EncumbrancesProcessingHolder) CompositePurchaseOrder(org.folio.rest.jaxrs.model.CompositePurchaseOrder) RequestContext(org.folio.rest.core.models.RequestContext) Map(java.util.Map) Encumbrance(org.folio.rest.acq.model.finance.Encumbrance) LEDGER_NOT_FOUND_FOR_TRANSACTION(org.folio.rest.core.exceptions.ErrorCodes.LEDGER_NOT_FOUND_FOR_TRANSACTION) Collection(java.util.Collection) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder) ErrorCodes(org.folio.rest.core.exceptions.ErrorCodes) CompletionException(java.util.concurrent.CompletionException) FiscalYearService(org.folio.service.finance.FiscalYearService) FundDistribution(org.folio.rest.jaxrs.model.FundDistribution) BUDGET_NOT_FOUND_FOR_TRANSACTION(org.folio.rest.core.exceptions.ErrorCodes.BUDGET_NOT_FOUND_FOR_TRANSACTION) MonetaryOperators(org.javamoney.moneta.function.MonetaryOperators) Objects(java.util.Objects) Error(org.folio.rest.jaxrs.model.Error) List(java.util.List) Collectors.toList(java.util.stream.Collectors.toList) Logger(org.apache.logging.log4j.Logger) CompletionStage(java.util.concurrent.CompletionStage) ERROR_REMOVING_INVOICE_LINE_ENCUMBRANCES(org.folio.rest.core.exceptions.ErrorCodes.ERROR_REMOVING_INVOICE_LINE_ENCUMBRANCES) CompositePoLine(org.folio.rest.jaxrs.model.CompositePoLine) Tags(org.folio.rest.acq.model.finance.Tags) HelperUtils.calculateEstimatedPrice(org.folio.orders.utils.HelperUtils.calculateEstimatedPrice) HttpStatus(org.folio.HttpStatus) Parameter(org.folio.rest.jaxrs.model.Parameter) BUDGET_IS_INACTIVE(org.folio.rest.core.exceptions.ErrorCodes.BUDGET_IS_INACTIVE) LogManager(org.apache.logging.log4j.LogManager) Collections(java.util.Collections) MonetaryAmount(javax.money.MonetaryAmount) FolioVertxCompletableFuture(org.folio.completablefuture.FolioVertxCompletableFuture) CompletableFuture(java.util.concurrent.CompletableFuture) CompletionException(java.util.concurrent.CompletionException) ArrayList(java.util.ArrayList) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder)

Example 4 with EncumbranceRelationsHolder

use of org.folio.models.EncumbranceRelationsHolder in project mod-orders by folio-org.

the class FundsDistributionService method distributeFunds.

public <T extends EncumbranceRelationsHolder> List<T> distributeFunds(List<T> holders) {
    Map<CompositePoLine, List<EncumbranceRelationsHolder>> lineHoldersMap = holders.stream().filter(holder -> Objects.nonNull(holder.getPoLine())).collect(Collectors.groupingBy(EncumbranceRelationsHolder::getPoLine));
    lineHoldersMap.forEach((poLine, encumbranceRelationsHolders) -> {
        poLine.getCost().setPoLineEstimatedPrice(HelperUtils.calculateEstimatedPrice(poLine.getCost()).getNumber().doubleValue());
        CurrencyUnit poLineCurrency = Monetary.getCurrency(poLine.getCost().getCurrency());
        CurrencyConversion conversion = encumbranceRelationsHolders.stream().map(EncumbranceRelationsHolder::getPoLineToFyConversion).findFirst().get();
        MonetaryAmount expectedTotal = Money.of(poLine.getCost().getPoLineEstimatedPrice(), poLineCurrency).with(conversion).with(getDefaultRounding());
        MonetaryAmount calculatedTotal = encumbranceRelationsHolders.stream().map(EncumbranceRelationsHolder::getFundDistribution).map(fundDistribution -> getDistributionAmount(fundDistribution, expectedTotal, poLineCurrency, conversion)).reduce((money, money2) -> Money.from(MonetaryFunctions.sum(money, money2))).orElseGet(() -> Money.zero(poLineCurrency));
        MonetaryAmount remainder = expectedTotal.abs().subtract(calculatedTotal.abs());
        int remainderSignum = remainder.signum();
        MonetaryAmount smallestUnit = getSmallestUnit(expectedTotal, remainderSignum);
        for (ListIterator<EncumbranceRelationsHolder> iterator = getIterator(encumbranceRelationsHolders, remainderSignum); isIteratorHasNext(iterator, remainderSignum); ) {
            final EncumbranceRelationsHolder holder = iteratorNext(iterator, remainderSignum);
            CurrencyUnit fyCurrency = Monetary.getCurrency(holder.getCurrency());
            MonetaryAmount initialAmount = getDistributionAmount(holder.getFundDistribution(), expectedTotal, poLineCurrency, conversion);
            if (FundDistribution.DistributionType.PERCENTAGE.equals(holder.getFundDistribution().getDistributionType()) && !remainder.isZero()) {
                initialAmount = initialAmount.add(smallestUnit);
                remainder = remainder.abs().subtract(smallestUnit.abs()).multiply(remainderSignum);
            }
            MonetaryAmount expended = Optional.of(holder).map(EncumbranceRelationsHolder::getNewEncumbrance).map(Transaction::getEncumbrance).map(Encumbrance::getAmountExpended).map(aDouble -> Money.of(aDouble, fyCurrency)).orElse(Money.zero(fyCurrency));
            MonetaryAmount awaitingPayment = Optional.of(holder).map(EncumbranceRelationsHolder::getNewEncumbrance).map(Transaction::getEncumbrance).map(Encumbrance::getAmountAwaitingPayment).map(aDouble -> Money.of(aDouble, fyCurrency)).orElse(Money.zero(fyCurrency));
            MonetaryAmount amount = MonetaryFunctions.max().apply(initialAmount.subtract(expended).subtract(awaitingPayment), Money.zero(fyCurrency));
            holder.getNewEncumbrance().setAmount(amount.getNumber().doubleValue());
            holder.getNewEncumbrance().getEncumbrance().setInitialAmountEncumbered(initialAmount.getNumber().doubleValue());
        }
    });
    return holders;
}
Also used : Monetary(javax.money.Monetary) CurrencyConversion(javax.money.convert.CurrencyConversion) ListIterator(java.util.ListIterator) CurrencyUnit(javax.money.CurrencyUnit) HelperUtils(org.folio.orders.utils.HelperUtils) Money(org.javamoney.moneta.Money) MonetaryFunctions(org.javamoney.moneta.function.MonetaryFunctions) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder) Transaction(org.folio.rest.acq.model.finance.Transaction) FundDistribution(org.folio.rest.jaxrs.model.FundDistribution) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) MonetaryOperators(org.javamoney.moneta.function.MonetaryOperators) List(java.util.List) CompositePoLine(org.folio.rest.jaxrs.model.CompositePoLine) Map(java.util.Map) Encumbrance(org.folio.rest.acq.model.finance.Encumbrance) Monetary.getDefaultRounding(javax.money.Monetary.getDefaultRounding) Optional(java.util.Optional) MonetaryAmount(javax.money.MonetaryAmount) CurrencyUnit(javax.money.CurrencyUnit) MonetaryAmount(javax.money.MonetaryAmount) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder) Encumbrance(org.folio.rest.acq.model.finance.Encumbrance) CompositePoLine(org.folio.rest.jaxrs.model.CompositePoLine) CurrencyConversion(javax.money.convert.CurrencyConversion) List(java.util.List)

Example 5 with EncumbranceRelationsHolder

use of org.folio.models.EncumbranceRelationsHolder in project mod-orders by folio-org.

the class EncumbranceRelationsHoldersBuilderTest method initMocks.

@BeforeEach
public void initMocks() {
    MockitoAnnotations.openMocks(this);
    order = new CompositePurchaseOrder().withId(UUID.randomUUID().toString()).withReEncumber(true).withOrderType(CompositePurchaseOrder.OrderType.ONGOING).withOngoing(new Ongoing().withIsSubscription(false));
    distribution1 = new FundDistribution().withFundId(UUID.randomUUID().toString()).withDistributionType(FundDistribution.DistributionType.PERCENTAGE).withValue(100d).withEncumbrance(UUID.randomUUID().toString());
    line1 = new CompositePoLine().withId(UUID.randomUUID().toString()).withCost(new Cost().withCurrency("USD").withListUnitPrice(68d).withQuantityPhysical(1)).withPurchaseOrderId(order.getId()).withFundDistribution(Collections.singletonList(distribution1));
    distribution2 = new FundDistribution().withFundId(UUID.randomUUID().toString()).withDistributionType(FundDistribution.DistributionType.PERCENTAGE).withValue(100d).withEncumbrance(UUID.randomUUID().toString());
    line2 = new CompositePoLine().withId(UUID.randomUUID().toString()).withCost(new Cost().withCurrency("USD").withListUnitPrice(34.95).withQuantityPhysical(1)).withPurchaseOrderId(order.getId()).withFundDistribution(Collections.singletonList(distribution2));
    distribution3 = new FundDistribution().withFundId(UUID.randomUUID().toString()).withDistributionType(FundDistribution.DistributionType.PERCENTAGE).withExpenseClassId(UUID.randomUUID().toString()).withValue(100d).withEncumbrance(UUID.randomUUID().toString());
    line3 = new CompositePoLine().withId(UUID.randomUUID().toString()).withCost(new Cost().withCurrency("EUR").withListUnitPrice(24.99).withQuantityPhysical(1)).withPurchaseOrderId(order.getId()).withFundDistribution(Collections.singletonList(distribution3));
    order.setCompositePoLines(List.of(line1, line2, line3));
    newEncumbrance1 = new Transaction().withFromFundId(distribution1.getFundId()).withSource(PO_LINE).withEncumbrance(new Encumbrance().withOrderType(ONGOING).withReEncumber(true).withOrderStatus(OPEN).withStatus(UNRELEASED).withSubscription(false).withSourcePurchaseOrderId(order.getId()).withSourcePoLineId(line1.getId()));
    newEncumbrance2 = new Transaction().withFromFundId(distribution2.getFundId()).withSource(PO_LINE).withEncumbrance(new Encumbrance().withOrderType(ONGOING).withReEncumber(true).withOrderStatus(OPEN).withStatus(UNRELEASED).withSubscription(false).withSourcePurchaseOrderId(order.getId()).withSourcePoLineId(line2.getId()));
    newEncumbrance3 = new Transaction().withFromFundId(distribution3.getFundId()).withSource(PO_LINE).withExpenseClassId(distribution3.getExpenseClassId()).withEncumbrance(new Encumbrance().withOrderType(ONGOING).withReEncumber(true).withOrderStatus(OPEN).withStatus(UNRELEASED).withSubscription(false).withSourcePurchaseOrderId(order.getId()).withSourcePoLineId(line3.getId()));
    holder1 = new EncumbranceRelationsHolder().withPurchaseOrder(order).withPoLine(line1).withFundDistribution(distribution1).withNewEncumbrance(newEncumbrance1);
    holder2 = new EncumbranceRelationsHolder().withPurchaseOrder(order).withPoLine(line2).withFundDistribution(distribution2).withNewEncumbrance(newEncumbrance2);
    holder3 = new EncumbranceRelationsHolder().withPurchaseOrder(order).withPoLine(line3).withFundDistribution(distribution3).withNewEncumbrance(newEncumbrance3);
}
Also used : FundDistribution(org.folio.rest.jaxrs.model.FundDistribution) Transaction(org.folio.rest.acq.model.finance.Transaction) Encumbrance(org.folio.rest.acq.model.finance.Encumbrance) EncumbranceRelationsHolder(org.folio.models.EncumbranceRelationsHolder) CompositePoLine(org.folio.rest.jaxrs.model.CompositePoLine) Ongoing(org.folio.rest.jaxrs.model.Ongoing) CompositePurchaseOrder(org.folio.rest.jaxrs.model.CompositePurchaseOrder) Cost(org.folio.rest.jaxrs.model.Cost) BeforeEach(org.junit.jupiter.api.BeforeEach)

Aggregations

EncumbranceRelationsHolder (org.folio.models.EncumbranceRelationsHolder)24 Transaction (org.folio.rest.acq.model.finance.Transaction)18 Test (org.junit.jupiter.api.Test)15 ArrayList (java.util.ArrayList)13 FundDistribution (org.folio.rest.jaxrs.model.FundDistribution)12 Budget (org.folio.rest.acq.model.finance.Budget)11 Encumbrance (org.folio.rest.acq.model.finance.Encumbrance)10 CompositePoLine (org.folio.rest.jaxrs.model.CompositePoLine)9 Objects (java.util.Objects)8 List (java.util.List)7 MonetaryAmount (javax.money.MonetaryAmount)7 Map (java.util.Map)6 CurrencyConversion (javax.money.convert.CurrencyConversion)6 Cost (org.folio.rest.jaxrs.model.Cost)6 Optional (java.util.Optional)5 Collectors (java.util.stream.Collectors)5 Collectors.toList (java.util.stream.Collectors.toList)5 CompositePurchaseOrder (org.folio.rest.jaxrs.model.CompositePurchaseOrder)5 Collectors.groupingBy (java.util.stream.Collectors.groupingBy)4 Fund (org.folio.rest.acq.model.finance.Fund)4