use of org.folio.models.InvoiceWorkflowDataHolder in project mod-invoice by folio-org.
the class FundAvailabilityHolderValidatorTest method checkEnoughMoneyInBudgetShouldThrowFundCannotBePaidIfTransactionsAmountDifferenceGreaterThanBudgetRemainingAmount.
@Test
void checkEnoughMoneyInBudgetShouldThrowFundCannotBePaidIfTransactionsAmountDifferenceGreaterThanBudgetRemainingAmount() {
String fiscalYearId = UUID.randomUUID().toString();
String fundId = UUID.randomUUID().toString();
String budgetId = UUID.randomUUID().toString();
String ledgerId = UUID.randomUUID().toString();
Transaction existingTransaction = new Transaction().withTransactionType(Transaction.TransactionType.PENDING_PAYMENT).withAmount(50d).withFiscalYearId(fiscalYearId).withFromFundId(fundId).withCurrency("USD");
Transaction newTransaction = new Transaction().withTransactionType(Transaction.TransactionType.PENDING_PAYMENT).withAmount(60d).withFiscalYearId(fiscalYearId).withFromFundId(fundId).withCurrency("USD");
Fund fund = new Fund().withId(fundId).withName("TestFund").withLedgerId(ledgerId).withCode("FC").withFundStatus(Fund.FundStatus.ACTIVE);
Budget budget = new Budget().withId(budgetId).withFiscalYearId(fiscalYearId).withFundId(fundId).withAllocated(59d).withTotalFunding(59d).withAvailable(9d).withUnavailable(50d).withAwaitingPayment(50D).withAllowableExpenditure(100d);
List<InvoiceWorkflowDataHolder> holders = new ArrayList<>();
InvoiceWorkflowDataHolder holder = new InvoiceWorkflowDataHolder().withFund(fund).withExistingTransaction(existingTransaction).withNewTransaction(newTransaction).withBudget(budget).withRestrictExpenditures(true).withFiscalYear(new FiscalYear().withId(fiscalYearId).withCurrency("USD"));
holders.add(holder);
HttpException httpException = assertThrows(HttpException.class, () -> fundAvailabilityValidator.validate(holders));
assertEquals(422, httpException.getCode());
Error error = httpException.getErrors().getErrors().get(0);
assertEquals(FUND_CANNOT_BE_PAID.getCode(), error.getCode());
assertEquals(Collections.singletonList("FC").toString(), error.getParameters().get(0).getValue());
}
use of org.folio.models.InvoiceWorkflowDataHolder in project mod-invoice by folio-org.
the class FundAvailabilityHolderValidatorTest method checkEnoughMoneyInBudgetShouldPassIfTransactionsAmountDifferenceGreaterThanBudgetRemainingAmountAndBudgetAllowableExpenditureIsNull.
@Test
void checkEnoughMoneyInBudgetShouldPassIfTransactionsAmountDifferenceGreaterThanBudgetRemainingAmountAndBudgetAllowableExpenditureIsNull() {
String fiscalYearId = UUID.randomUUID().toString();
String fundId = UUID.randomUUID().toString();
String budgetId = UUID.randomUUID().toString();
String ledgerId = UUID.randomUUID().toString();
Transaction existingTransaction = new Transaction().withTransactionType(Transaction.TransactionType.PENDING_PAYMENT).withAmount(50d).withFiscalYearId(fiscalYearId).withFromFundId(fundId).withCurrency("USD");
Transaction newTransaction = new Transaction().withTransactionType(Transaction.TransactionType.PENDING_PAYMENT).withAmount(60d).withFiscalYearId(fiscalYearId).withFromFundId(fundId).withCurrency("USD");
Fund fund = new Fund().withId(fundId).withName("TestFund").withLedgerId(ledgerId).withCode("FC").withFundStatus(Fund.FundStatus.ACTIVE);
Budget budget = new Budget().withId(budgetId).withFiscalYearId(fiscalYearId).withFundId(fundId).withAllocated(59d).withTotalFunding(59d).withAvailable(0d).withUnavailable(50d).withAwaitingPayment(50D).withAllowableExpenditure(null);
List<InvoiceWorkflowDataHolder> holders = new ArrayList<>();
InvoiceWorkflowDataHolder holder = new InvoiceWorkflowDataHolder().withFund(fund).withExistingTransaction(existingTransaction).withNewTransaction(newTransaction).withBudget(budget).withRestrictExpenditures(true).withFiscalYear(new FiscalYear().withId(fiscalYearId).withCurrency("USD"));
holders.add(holder);
assertDoesNotThrow(() -> fundAvailabilityValidator.validate(holders));
}
use of org.folio.models.InvoiceWorkflowDataHolder in project mod-invoice by folio-org.
the class FundAvailabilityHolderValidatorTest method shouldPassValidationWhenBudgetRestrictedAndFinalExpendedValueGreaterThenMaxBudgetExpended.
@Test
void shouldPassValidationWhenBudgetRestrictedAndFinalExpendedValueGreaterThenMaxBudgetExpended() {
String fiscalYearId = UUID.randomUUID().toString();
String fundId = UUID.randomUUID().toString();
String budgetId = UUID.randomUUID().toString();
String ledgerId = UUID.randomUUID().toString();
FiscalYear fiscalYear = new FiscalYear().withCurrency("USD").withId(fiscalYearId);
Fund fund = new Fund().withId(fundId).withName("TestFund").withLedgerId(ledgerId).withCode("FC").withFundStatus(Fund.FundStatus.ACTIVE);
Budget budget = new Budget().withId(budgetId).withFiscalYearId(fiscalYearId).withFundId(fundId).withAllocated(260d).withTotalFunding(260d).withAvailable(0d).withUnavailable(290d).withEncumbered(250d).withAwaitingPayment(30d).withExpenditures(10d).withAllowableExpenditure(100d).withAllowableExpenditure(110d);
List<InvoiceWorkflowDataHolder> holders = new ArrayList<>();
Transaction encumbrance = new Transaction().withId(UUID.randomUUID().toString()).withAmount(250d).withCurrency("USD");
Transaction linePendingPayment = new Transaction().withAmount(245d).withAwaitingPayment(new AwaitingPayment().withEncumbranceId(encumbrance.getId()).withReleaseEncumbrance(false)).withCurrency("USD");
InvoiceWorkflowDataHolder holder = new InvoiceWorkflowDataHolder().withFund(fund).withBudget(budget).withRestrictExpenditures(true).withFiscalYear(fiscalYear).withNewTransaction(linePendingPayment).withEncumbrance(encumbrance);
holders.add(holder);
HttpException httpException = assertThrows(HttpException.class, () -> fundAvailabilityValidator.validate(holders));
assertEquals(422, httpException.getCode());
Error error = httpException.getErrors().getErrors().get(0);
assertEquals(FUND_CANNOT_BE_PAID.getCode(), error.getCode());
assertEquals(Collections.singletonList("FC").toString(), error.getParameters().get(0).getValue());
}
use of org.folio.models.InvoiceWorkflowDataHolder in project mod-invoice by folio-org.
the class BudgetExpenseClassTest method shouldThrowExceptionWithBudgetExpenseClassNotFoundCodeWhenCheckExpenseClassesWithoutExpenseClasses.
@Test
void shouldThrowExceptionWithBudgetExpenseClassNotFoundCodeWhenCheckExpenseClassesWithoutExpenseClasses() {
String notAssignedExpenseClassId = UUID.randomUUID().toString();
String activeExpenseClassId = UUID.randomUUID().toString();
FundDistribution fundDistributionWithActiveExpenseClass = new FundDistribution().withFundId(UUID.randomUUID().toString()).withExpenseClassId(activeExpenseClassId);
FundDistribution fundDistributionWithNotAssignedExpenseClass = new FundDistribution().withFundId(UUID.randomUUID().toString()).withExpenseClassId(notAssignedExpenseClassId);
FundDistribution fundDistributionWithoutExpenseClass = new FundDistribution().withFundId(UUID.randomUUID().toString());
InvoiceLine invoiceLine = new InvoiceLine().withFundDistributions(Arrays.asList(fundDistributionWithActiveExpenseClass, fundDistributionWithoutExpenseClass));
List<InvoiceLine> invoiceLines = Collections.singletonList(invoiceLine);
Adjustment adjustment = new Adjustment().withFundDistributions(Collections.singletonList(fundDistributionWithNotAssignedExpenseClass));
Invoice invoice = new Invoice().withAdjustments(Collections.singletonList(adjustment));
BudgetExpenseClass active = new BudgetExpenseClass().withBudgetId(UUID.randomUUID().toString()).withExpenseClassId(activeExpenseClassId).withStatus(BudgetExpenseClass.Status.ACTIVE).withId(UUID.randomUUID().toString());
Fund noExpenseClassFund = new Fund().withCode("no expense class fund");
ExpenseClass notAssignedExpenseClass = new ExpenseClass().withName("not assigned class");
List<InvoiceWorkflowDataHolder> holders = new ArrayList<>();
InvoiceWorkflowDataHolder holder1 = new InvoiceWorkflowDataHolder().withInvoice(invoice).withInvoiceLine(invoiceLine).withFundDistribution(fundDistributionWithActiveExpenseClass).withBudget(new Budget().withFundId(UUID.randomUUID().toString())).withExpenseClass(new ExpenseClass().withId(activeExpenseClassId));
InvoiceWorkflowDataHolder holder2 = new InvoiceWorkflowDataHolder().withInvoice(invoice).withInvoiceLine(invoiceLine).withBudget(new Budget().withFundId(UUID.randomUUID().toString())).withFundDistribution(fundDistributionWithoutExpenseClass);
InvoiceWorkflowDataHolder holder3 = new InvoiceWorkflowDataHolder().withInvoice(invoice).withAdjustment(adjustment).withFundDistribution(fundDistributionWithNotAssignedExpenseClass).withExpenseClass(notAssignedExpenseClass).withBudget(new Budget().withFundId(UUID.randomUUID().toString())).withFund(noExpenseClassFund);
holders.add(holder1);
holders.add(holder2);
holders.add(holder3);
when(restClient.get(any(RequestEntry.class), any(), any())).thenAnswer(invocation -> {
RequestEntry requestEntry = invocation.getArgument(0);
List<BudgetExpenseClass> budgetExpenseClasses = requestEntry.buildEndpoint().contains(notAssignedExpenseClassId) ? Collections.emptyList() : Collections.singletonList(active);
return CompletableFuture.completedFuture(new BudgetExpenseClassCollection().withBudgetExpenseClasses(budgetExpenseClasses).withTotalRecords(1));
});
when(requestContext.getContext()).thenReturn(Vertx.vertx().getOrCreateContext());
CompletableFuture<List<InvoiceWorkflowDataHolder>> future = budgetExpenseClassService.checkExpenseClasses(holders, requestContext);
ExecutionException executionException = assertThrows(ExecutionException.class, future::get);
assertThat(executionException.getCause(), instanceOf(HttpException.class));
HttpException exception = (HttpException) executionException.getCause();
assertEquals(400, exception.getCode());
Errors errors = exception.getErrors();
Error error = errors.getErrors().get(0);
assertEquals(BUDGET_EXPENSE_CLASS_NOT_FOUND.getCode(), error.getCode());
String expenseClassNameFromError = error.getParameters().stream().filter(parameter -> parameter.getKey().equals(EXPENSE_CLASS_NAME)).findFirst().get().getValue();
assertEquals(notAssignedExpenseClass.getName(), expenseClassNameFromError);
String fundCodeFromError = error.getParameters().stream().filter(parameter -> parameter.getKey().equals(FUND_CODE)).findFirst().get().getValue();
assertEquals(noExpenseClassFund.getCode(), fundCodeFromError);
}
use of org.folio.models.InvoiceWorkflowDataHolder in project mod-invoice by folio-org.
the class FundAvailabilityHolderValidator method calculateNewExpendedAmount.
private MonetaryAmount calculateNewExpendedAmount(List<InvoiceWorkflowDataHolder> dataHolders) {
CurrencyUnit currency = Monetary.getCurrency(dataHolders.get(0).getFyCurrency());
return dataHolders.stream().map(holder -> {
MonetaryAmount newTransactionAmount = Money.of(holder.getNewTransaction().getAmount(), holder.getFyCurrency());
MonetaryAmount existingTransactionAmount = Optional.ofNullable(holder.getExistingTransaction()).map(transaction -> Money.of(transaction.getAmount(), transaction.getCurrency())).orElseGet(() -> Money.zero(Monetary.getCurrency(holder.getFyCurrency())));
MonetaryAmount encumbranceAmount = Optional.ofNullable(holder.getEncumbrance()).map(transaction -> Money.of(transaction.getAmount(), transaction.getCurrency())).orElseGet(() -> Money.zero(Monetary.getCurrency(holder.getFyCurrency())));
MonetaryAmount transactionAmountDif = newTransactionAmount.subtract(existingTransactionAmount);
MonetaryAmount newExpendedAmount = transactionAmountDif;
if (transactionAmountDif.isPositive()) {
newExpendedAmount = MonetaryFunctions.max().apply(transactionAmountDif.subtract(encumbranceAmount), Money.zero(currency));
MonetaryAmount encumbranceReminder = MonetaryFunctions.max().apply(encumbranceAmount.subtract(newExpendedAmount).add(existingTransactionAmount), Money.zero(currency));
Optional.ofNullable(holder.getEncumbrance()).ifPresent(transaction -> transaction.setAmount(encumbranceReminder.getNumber().doubleValue()));
}
return newExpendedAmount;
}).reduce(MonetaryFunctions::sum).orElseGet(() -> Money.zero(currency));
}
Aggregations