FINERACT-1500:SavingsHoldAccountLien
This commit is contained in:
committed by
Aleksandar Vidakovic
parent
4a5919a4a7
commit
a2be1eb985
+1
@@ -142,6 +142,7 @@ public class SavingsApiConstants {
|
|||||||
|
|
||||||
// transaction parameters
|
// transaction parameters
|
||||||
public static final String transactionDateParamName = "transactionDate";
|
public static final String transactionDateParamName = "transactionDate";
|
||||||
|
public static final String lienParamName = "lien";
|
||||||
public static final String transactionAmountParamName = "transactionAmount";
|
public static final String transactionAmountParamName = "transactionAmount";
|
||||||
public static final String paymentDetailDataParamName = "paymentDetailData";
|
public static final String paymentDetailDataParamName = "paymentDetailData";
|
||||||
public static final String runningBalanceParamName = "runningBalance";
|
public static final String runningBalanceParamName = "runningBalance";
|
||||||
|
|||||||
+20
-3
@@ -23,6 +23,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.activate
|
|||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.bankNumberParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.bankNumberParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.checkNumberParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.checkNumberParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.closedOnDateParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.closedOnDateParamName;
|
||||||
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lienParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.paymentTypeIdParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.paymentTypeIdParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.receiptNumberParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.receiptNumberParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.routingCodeParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.routingCodeParamName;
|
||||||
@@ -68,7 +69,7 @@ public class SavingsAccountTransactionDataValidator {
|
|||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
private static final Set<String> SAVINGS_ACCOUNT_HOLD_AMOUNT_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
private static final Set<String> SAVINGS_ACCOUNT_HOLD_AMOUNT_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||||
Arrays.asList(transactionDateParamName, SavingsApiConstants.dateFormatParamName, SavingsApiConstants.localeParamName,
|
Arrays.asList(transactionDateParamName, SavingsApiConstants.dateFormatParamName, SavingsApiConstants.localeParamName,
|
||||||
transactionAmountParamName));
|
transactionAmountParamName, lienParamName));
|
||||||
private final ConfigurationDomainService configurationDomainService;
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -206,6 +207,7 @@ public class SavingsAccountTransactionDataValidator {
|
|||||||
|
|
||||||
public SavingsAccountTransaction validateHoldAndAssembleForm(final String json, final SavingsAccount account, final AppUser createdUser,
|
public SavingsAccountTransaction validateHoldAndAssembleForm(final String json, final SavingsAccount account, final AppUser createdUser,
|
||||||
final boolean backdatedTxnsAllowedTill) {
|
final boolean backdatedTxnsAllowedTill) {
|
||||||
|
|
||||||
if (StringUtils.isBlank(json)) {
|
if (StringUtils.isBlank(json)) {
|
||||||
throw new InvalidJsonException();
|
throw new InvalidJsonException();
|
||||||
}
|
}
|
||||||
@@ -222,6 +224,7 @@ public class SavingsAccountTransactionDataValidator {
|
|||||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName, element);
|
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName, element);
|
||||||
baseDataValidator.reset().parameter(transactionAmountParamName).value(amount).notNull().positiveAmount();
|
baseDataValidator.reset().parameter(transactionAmountParamName).value(amount).notNull().positiveAmount();
|
||||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
|
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
|
||||||
|
|
||||||
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
|
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
|
||||||
boolean isActive = account.isActive();
|
boolean isActive = account.isActive();
|
||||||
|
|
||||||
@@ -230,8 +233,22 @@ public class SavingsAccountTransactionDataValidator {
|
|||||||
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
|
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
|
||||||
}
|
}
|
||||||
account.holdAmount(amount);
|
account.holdAmount(amount);
|
||||||
if (account.getWithdrawableBalance().compareTo(BigDecimal.ZERO) < 0) {
|
|
||||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId());
|
if (account.getEnforceMinRequiredBalance()) {
|
||||||
|
if (account.getWithdrawableBalance().compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean lien = false;
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(lienParamName, element)) {
|
||||||
|
lien = this.fromApiJsonHelper.extractBooleanNamed(lienParamName, element);
|
||||||
|
if (!lien) {
|
||||||
|
if (account.getWithdrawableBalanceWithoutMinimumBalance().compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDate lastTransactionDate = null;
|
LocalDate lastTransactionDate = null;
|
||||||
|
|||||||
+8
@@ -1935,6 +1935,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
|||||||
return this.savingsOfficer;
|
return this.savingsOfficer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getEnforceMinRequiredBalance() {
|
||||||
|
return this.enforceMinRequiredBalance;
|
||||||
|
}
|
||||||
|
|
||||||
public void unassignSavingsOfficer() {
|
public void unassignSavingsOfficer() {
|
||||||
this.savingsOfficer = null;
|
this.savingsOfficer = null;
|
||||||
}
|
}
|
||||||
@@ -3367,6 +3371,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
|||||||
.subtract(this.getSavingsHoldAmount());
|
.subtract(this.getSavingsHoldAmount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getWithdrawableBalanceWithoutMinimumBalance() {
|
||||||
|
return getAccountBalance().subtract(this.getOnHoldFunds()).subtract(this.getSavingsHoldAmount());
|
||||||
|
}
|
||||||
|
|
||||||
public TaxGroup getTaxGroup() {
|
public TaxGroup getTaxGroup() {
|
||||||
return this.taxGroup;
|
return this.taxGroup;
|
||||||
}
|
}
|
||||||
|
|||||||
+69
-1
@@ -2156,7 +2156,7 @@ public class ClientSavingsIntegrationTest {
|
|||||||
assertEquals(Float.parseFloat(DEPOSIT_AMOUNT), depositTransaction.get("amount"), "Verifying Deposit Amount");
|
assertEquals(Float.parseFloat(DEPOSIT_AMOUNT), depositTransaction.get("amount"), "Verifying Deposit Amount");
|
||||||
|
|
||||||
Integer holdTransactionId = (Integer) this.savingsAccountHelper.holdAmountInSavingsAccount(savingsId, String.valueOf(balance - 100),
|
Integer holdTransactionId = (Integer) this.savingsAccountHelper.holdAmountInSavingsAccount(savingsId, String.valueOf(balance - 100),
|
||||||
SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
|
false, SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||||
error = (List) savingsAccountHelperValidationError.withdrawalFromSavingsAccount(savingsId, "300",
|
error = (List) savingsAccountHelperValidationError.withdrawalFromSavingsAccount(savingsId, "300",
|
||||||
SavingsAccountHelper.TRANSACTION_DATE_PLUS_ONE, CommonConstants.RESPONSE_ERROR);
|
SavingsAccountHelper.TRANSACTION_DATE_PLUS_ONE, CommonConstants.RESPONSE_ERROR);
|
||||||
assertEquals("error.msg.savingsaccount.transaction.insufficient.account.balance",
|
assertEquals("error.msg.savingsaccount.transaction.insufficient.account.balance",
|
||||||
@@ -2175,6 +2175,74 @@ public class ClientSavingsIntegrationTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
public void testSavingsAccountLienStatus() {
|
||||||
|
|
||||||
|
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||||
|
SavingsAccountHelper savingsAccountHelperValidationError = new SavingsAccountHelper(this.requestSpec,
|
||||||
|
new ResponseSpecBuilder().build());
|
||||||
|
|
||||||
|
final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||||
|
final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse);
|
||||||
|
|
||||||
|
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||||
|
|
||||||
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||||
|
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||||
|
|
||||||
|
final String minBalanceForInterestCalculation = null;
|
||||||
|
final String minRequiredBalance = null;
|
||||||
|
final String enforceMinRequiredBalance = "false";
|
||||||
|
final boolean allowOverdraft = false;
|
||||||
|
final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE,
|
||||||
|
minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft);
|
||||||
|
Assertions.assertNotNull(savingsProductID);
|
||||||
|
|
||||||
|
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL);
|
||||||
|
Assertions.assertNotNull(savingsProductID);
|
||||||
|
|
||||||
|
HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(this.requestSpec, this.responseSpec, savingsId);
|
||||||
|
SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
|
||||||
|
|
||||||
|
savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsId);
|
||||||
|
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
|
||||||
|
|
||||||
|
savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId);
|
||||||
|
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
|
||||||
|
|
||||||
|
List<HashMap> error = (List) savingsAccountHelperValidationError.holdAmountInSavingsAccount(savingsId, "1500", false,
|
||||||
|
SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_ERROR); // lien:false
|
||||||
|
|
||||||
|
assertEquals("validation.msg.savingsaccount.insufficient balance", error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
||||||
|
|
||||||
|
Integer holdTransactionId = (Integer) this.savingsAccountHelper.holdAmountInSavingsAccount(savingsId, "1500", true,
|
||||||
|
SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||||
|
|
||||||
|
HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||||
|
|
||||||
|
Float balance = Float.parseFloat("-500");
|
||||||
|
|
||||||
|
assertEquals(balance, summary.get("availableBalance"), "Verifying available Balance is -500");
|
||||||
|
|
||||||
|
Integer depositTransactionId = (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, "1000",
|
||||||
|
SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||||
|
Calendar todaysDate = Calendar.getInstance();
|
||||||
|
final String TRANSACTION_DATE = dateFormat.format(todaysDate.getTime());
|
||||||
|
|
||||||
|
ArrayList<HashMap> savingsAccountErrorData = (ArrayList<HashMap>) validationErrorHelper.withdrawalFromSavingsAccount(savingsId,
|
||||||
|
"1000", TRANSACTION_DATE, CommonConstants.RESPONSE_ERROR);
|
||||||
|
|
||||||
|
assertEquals("error.msg.savingsaccount.transaction.insufficient.account.balance",
|
||||||
|
savingsAccountErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
||||||
|
|
||||||
|
Integer withdrawTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500", TRANSACTION_DATE,
|
||||||
|
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||||
|
|
||||||
|
Assertions.assertNotNull(withdrawTransactionId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* incorrect savings account balance when charge transaction is reversed during an overdraft recalculate Daily
|
* incorrect savings account balance when charge transaction is reversed during an overdraft recalculate Daily
|
||||||
* Balances
|
* Balances
|
||||||
|
|||||||
+15
-2
@@ -369,10 +369,11 @@ public class SavingsAccountHelper {
|
|||||||
getActivatedSavingsAsJSON(), isBlock);
|
getActivatedSavingsAsJSON(), isBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object holdAmountInSavingsAccount(final Integer savingsID, final String amount, String date, String jsonAttributeToGetback) {
|
public Object holdAmountInSavingsAccount(final Integer savingsID, final String amount, final Boolean lienStatus, String date,
|
||||||
|
String jsonAttributeToGetback) {
|
||||||
LOG.info("--------------------------------- SAVINGS TRANSACTION HOLD AMOUNT--------------------------------");
|
LOG.info("--------------------------------- SAVINGS TRANSACTION HOLD AMOUNT--------------------------------");
|
||||||
return performSavingActions(createSavingsTransactionURL(HOLD_AMOUNT_SAVINGS_COMMAND, savingsID),
|
return performSavingActions(createSavingsTransactionURL(HOLD_AMOUNT_SAVINGS_COMMAND, savingsID),
|
||||||
getSavingsTransactionJSON(amount, date), jsonAttributeToGetback);
|
getLienSavingsTransactionJSON(amount, date, lienStatus), jsonAttributeToGetback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer releaseAmount(final Integer savingsId, final Integer transactionId) {
|
public Integer releaseAmount(final Integer savingsId, final Integer transactionId) {
|
||||||
@@ -439,6 +440,18 @@ public class SavingsAccountHelper {
|
|||||||
return savingsAccountWithdrawalJson;
|
return savingsAccountWithdrawalJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getLienSavingsTransactionJSON(final String amount, final String transactionDate, final Boolean lien) {
|
||||||
|
final HashMap<String, Object> map = new HashMap<>();
|
||||||
|
map.put("locale", CommonConstants.LOCALE);
|
||||||
|
map.put("dateFormat", CommonConstants.DATE_FORMAT);
|
||||||
|
map.put("transactionDate", transactionDate);
|
||||||
|
map.put("transactionAmount", amount);
|
||||||
|
map.put("lien", lien);
|
||||||
|
String savingsAccountWithdrawalJson = new Gson().toJson(map);
|
||||||
|
LOG.info(savingsAccountWithdrawalJson);
|
||||||
|
return savingsAccountWithdrawalJson;
|
||||||
|
}
|
||||||
|
|
||||||
private String getSavingsTransactionPaymentTypeJSON(final String amount, final String transactionDate, final String paymentTypeId) {
|
private String getSavingsTransactionPaymentTypeJSON(final String amount, final String transactionDate, final String paymentTypeId) {
|
||||||
final HashMap<String, String> map = new HashMap<>();
|
final HashMap<String, String> map = new HashMap<>();
|
||||||
map.put("locale", CommonConstants.LOCALE);
|
map.put("locale", CommonConstants.LOCALE);
|
||||||
|
|||||||
Reference in New Issue
Block a user