Skip to content

Commit

Permalink
[MODFIN-352] Allow transaction processing for planned budgets + new a…
Browse files Browse the repository at this point in the history
…mount validation (#407)
  • Loading branch information
damien-git committed Apr 16, 2024
1 parent 33cf0d1 commit 98ad5f2
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/main/java/org/folio/rest/util/ErrorCodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public enum ErrorCodes {
"Could not find the budget for the encumbrance. The encumbrance fund id is probably not matching the fund id in the invoice line."),
BUDGET_IS_INACTIVE("budgetIsInactive", "Cannot create transaction from the not active budget {0}"),
BUDGET_RESTRICTED_EXPENDITURES_ERROR("budgetRestrictedExpendituresError", "Expenditure restriction does not allow this operation"),
BUDGET_RESTRICTED_ENCUMBRANCE_ERROR("budgetRestrictedEncumbranceError", "Encumbrance restriction does not allow this operation");
BUDGET_RESTRICTED_ENCUMBRANCE_ERROR("budgetRestrictedEncumbranceError", "Encumbrance restriction does not allow this operation"),
PAYMENT_OR_CREDIT_HAS_NEGATIVE_AMOUNT("paymentOrCreditHasNegativeAmount", "A payment or credit has a negative amount");
private final String code;
private final String description;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.folio.rest.jaxrs.model.Budget.BudgetStatus.ACTIVE;
import static org.folio.rest.jaxrs.model.Budget.BudgetStatus.PLANNED;
import static org.folio.rest.jaxrs.model.Transaction.TransactionType.ALLOCATION;
import static org.folio.rest.jaxrs.model.Transaction.TransactionType.CREDIT;
import static org.folio.rest.jaxrs.model.Transaction.TransactionType.ENCUMBRANCE;
Expand All @@ -37,6 +38,7 @@
import static org.folio.rest.util.ErrorCodes.BUDGET_RESTRICTED_ENCUMBRANCE_ERROR;
import static org.folio.rest.util.ErrorCodes.BUDGET_RESTRICTED_EXPENDITURES_ERROR;
import static org.folio.rest.util.ErrorCodes.MISSING_FUND_ID;
import static org.folio.rest.util.ErrorCodes.PAYMENT_OR_CREDIT_HAS_NEGATIVE_AMOUNT;

public class BatchTransactionChecks {
private static final Logger logger = LogManager.getLogger();
Expand Down Expand Up @@ -65,12 +67,13 @@ public static void sanityChecks(Batch batch) {
checkTransfer(transaction);
}
});
checkPaymentsAndCreditsAmounts(batch);
}

public static void checkBudgetsAreActive(BatchTransactionHolder holder) {
holder.getBudgets().forEach(budget -> {
if (budget.getBudgetStatus() != ACTIVE) {
throw new HttpException(400, String.format("Cannot process transactions because of an inactive budget for fund %s",
if (!List.of(ACTIVE, PLANNED).contains(budget.getBudgetStatus())) {
throw new HttpException(400, String.format("Cannot process transactions because a budget is not active or planned, fundId=%s",
holder.getFundCodeForBudget(budget)));
}
});
Expand Down Expand Up @@ -263,4 +266,17 @@ private static void checkRestrictedEncumbrance(Budget budget, String currency, B
throw new HttpException(422, error);
}
}

private static void checkPaymentsAndCreditsAmounts(Batch batch) {
List<Transaction> newPaymentsAndCredits = batch.getTransactionsToCreate().stream()
.filter(tr -> List.of(PAYMENT, CREDIT).contains(tr.getTransactionType()))
.toList();
for (Transaction tr : newPaymentsAndCredits) {
if (tr.getAmount() < 0) {
List<Parameter> parameters = singletonList(new Parameter().withKey("id").withValue(tr.getId()));
Error error = PAYMENT_OR_CREDIT_HAS_NEGATIVE_AMOUNT.toError().withParameters(parameters);
throw new HttpException(422, error);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,39 @@ void testEncumbranceRestrictionsWhenCreatingTwoEncumbrances(VertxTestContext tes
});
}

@Test
void testCreatePaymentWithNegativeAmount(VertxTestContext testContext) {
String paymentId = UUID.randomUUID().toString();
String encumbranceId = UUID.randomUUID().toString();
String invoiceId = UUID.randomUUID().toString();
String fundId = UUID.randomUUID().toString();
String fiscalYearId = UUID.randomUUID().toString();
String currency = "USD";

Transaction payment = new Transaction()
.withId(paymentId)
.withTransactionType(PAYMENT)
.withSourceInvoiceId(invoiceId)
.withFromFundId(fundId)
.withFiscalYearId(fiscalYearId)
.withAmount(-5d)
.withCurrency(currency)
.withInvoiceCancelled(false)
.withPaymentEncumbranceId(encumbranceId);

Batch batch = new Batch();
batch.getTransactionsToCreate().add(payment);

testContext.assertFailure(batchTransactionService.processBatch(batch, requestContext))
.onComplete(event -> {
testContext.verify(() -> {
assertThat(event.cause(), instanceOf(HttpException.class));
assertThat(((HttpException) event.cause()).getCode(), equalTo(422));
});
testContext.completeNow();
});
}

private void setupFundBudgetLedger(String fundId, String fiscalYearId, double budgetEncumbered,
double budgetAwaitingPayment, double budgetExpenditures, boolean restrictExpenditures, boolean restrictEncumbrance) {
String tenantId = "tenantname";
Expand Down

0 comments on commit 98ad5f2

Please sign in to comment.