Repository: fineract Updated Branches: refs/heads/develop 5b808fecc -> 12f80f4ad
FINERACT-482 block account changes Project: http://git-wip-us.apache.org/repos/asf/fineract/repo Commit: http://git-wip-us.apache.org/repos/asf/fineract/commit/7368c3f1 Tree: http://git-wip-us.apache.org/repos/asf/fineract/tree/7368c3f1 Diff: http://git-wip-us.apache.org/repos/asf/fineract/diff/7368c3f1 Branch: refs/heads/develop Commit: 7368c3f11add84ddf8dcee086eccc7b8f69d518a Parents: 6946f1c Author: ShruthiRajaram <shru...@confluxtechnologies.com> Authored: Wed Jul 12 17:59:18 2017 +0530 Committer: ShruthiRajaram <shru...@confluxtechnologies.com> Committed: Wed Jul 12 17:59:18 2017 +0530 ---------------------------------------------------------------------- .../ClientSavingsIntegrationTest.java | 12 ++++-- .../common/savings/SavingsAccountHelper.java | 1 + .../portfolio/savings/SavingsApiConstants.java | 1 + .../savings/api/SavingsApiSetConstants.java | 2 +- .../savings/data/SavingsAccountData.java | 21 ++++++---- .../SavingsAccountTransactionDataValidator.java | 38 ++++++++++++------ .../savings/domain/SavingsAccount.java | 41 +++++++++++++++----- .../domain/SavingsAccountTransaction.java | 4 ++ .../SavingsAccountReadPlatformServiceImpl.java | 15 +++++-- ...ntWritePlatformServiceJpaRepositoryImpl.java | 5 ++- ...0__savings_account_transaction_releaseId.sql | 4 ++ 11 files changed, 106 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java index b279163..1ae2609 100755 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java @@ -28,10 +28,12 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.CommonConstants; import org.apache.fineract.integrationtests.common.SchedulerJobHelper; @@ -2214,13 +2216,17 @@ public class ClientSavingsIntegrationTest { Integer holdTransactionId = (Integer) this.savingsAccountHelper.holdAmountInSavingsAccount(savingsId, String.valueOf(balance - 100), SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID); error = (List) savingsAccountHelperValidationError.withdrawalFromSavingsAccount(savingsId, "300", - SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_ERROR); + SavingsAccountHelper.TRANSACTION_DATE_PLUS_ONE, CommonConstants.RESPONSE_ERROR); assertEquals("error.msg.savingsaccount.transaction.insufficient.account.balance", error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); Integer releaseTransactionId = this.savingsAccountHelper.releaseAmount(savingsId, holdTransactionId); - withdrawTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "300", - SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID); + Date today = DateUtils.getDateOfTenant(); + String todayDate = today.toString(); + SimpleDateFormat dt1 = new SimpleDateFormat("dd MMM yyyy"); + todayDate = dt1.format(today).toString(); + withdrawTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "300", todayDate, + CommonConstants.RESPONSE_RESOURCE_ID); withdrawTransaction = this.savingsAccountHelper.getSavingsTransaction(savingsId, withdrawTransactionId); balance -= new Float("300"); assertEquals("Verifying Withdrawal Amount", new Float("300"), withdrawTransaction.get("amount")); http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java index c2cd4f9..d0752a3 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java @@ -69,6 +69,7 @@ public class SavingsAccountHelper { public static final String CREATED_DATE_PLUS_ONE = "09 January 2013"; public static final String CREATED_DATE_MINUS_ONE = "07 January 2013"; public static final String TRANSACTION_DATE = "01 March 2013"; + public static final String TRANSACTION_DATE_PLUS_ONE = "02 March 2013"; public static final String LAST_TRANSACTION_DATE = "01 March 2013"; public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL"; http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java index 1b8aa53..a2826ab 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java @@ -133,6 +133,7 @@ public class SavingsApiConstants { public static final String minBalanceForInterestCalculationParamName = "minBalanceForInterestCalculation"; public static final String withdrawBalanceParamName = "withdrawBalance"; public static final String onHoldFundsParamName = "onHoldFunds"; + public static final String savingsAmountOnHold = "savingsAmountOnHold"; public static final String withHoldTaxParamName = "withHoldTax"; public static final String taxGroupIdParamName = "taxGroupId"; http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java index 70ac7b4..36d319a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java @@ -65,7 +65,7 @@ public class SavingsApiSetConstants extends SavingsApiConstants { "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee", onHoldFundsParamName, nominalAnnualInterestRateOverdraftParamName, - minOverdraftForInterestCalculationParamName, datatables)); + minOverdraftForInterestCalculationParamName, datatables, savingsAmountOnHold)); protected static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>( Arrays.asList(idParamName, "accountId", accountNoParamName, "currency", "amount", dateParamName, http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java index d06bbe9..32a0630 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java @@ -76,6 +76,7 @@ public class SavingsAccountData { private final Integer daysToInactive; private final Integer daysToDormancy; private final Integer daysToEscheat; + private final BigDecimal savingsAmountOnHold; // associations private final SavingsAccountSummaryData summary; @@ -118,7 +119,7 @@ public class SavingsAccountData { final BigDecimal onHoldFunds, final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation, final boolean withHoldTax, final TaxGroupData taxGroup, final LocalDate lastActiveTransactionDate, final boolean isDormancyTrackingActive, final Integer daysToInactive, - final Integer daysToDormancy, final Integer daysToEscheat) { + final Integer daysToDormancy, final Integer daysToEscheat, final BigDecimal savingsAmountOnHold) { final Collection<SavingsProductData> productOptions = null; final Collection<StaffData> fieldOfficerOptions = null; @@ -142,7 +143,7 @@ public class SavingsAccountData { lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, - lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat); + lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold); } public static SavingsAccountData lookup(final Long accountId, final String accountNo, final EnumOptionData depositType) { @@ -204,6 +205,7 @@ public class SavingsAccountData { final Integer daysToInactive = null; final Integer daysToDormancy = null; final Integer daysToEscheat = null; + final BigDecimal savingsAmountOnHold = null; return new SavingsAccountData(accountId, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualInterestRate, @@ -214,7 +216,7 @@ public class SavingsAccountData { lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, - lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat); + lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold); } public static SavingsAccountData lookupWithProductDetails(final Long accountId, final String accountNo, @@ -274,6 +276,7 @@ public class SavingsAccountData { final Integer daysToInactive = null; final Integer daysToDormancy = null; final Integer daysToEscheat = null; + final BigDecimal savingsAmountOnHold = null; return new SavingsAccountData(accountId, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualInterestRate, @@ -284,7 +287,7 @@ public class SavingsAccountData { lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, - lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat); + lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold); } public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, final SavingsAccountData template, @@ -320,7 +323,7 @@ public class SavingsAccountData { account.minBalanceForInterestCalculation, account.onHoldFunds, account.nominalAnnualInterestRateOverdraft, account.minOverdraftForInterestCalculation, account.withHoldTax, account.taxGroup, account.lastActiveTransactionDate, account.isDormancyTrackingActive, account.daysToInactive, - account.daysToDormancy, account.daysToEscheat); + account.daysToDormancy, account.daysToEscheat, account.savingsAmountOnHold); } public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, @@ -345,7 +348,7 @@ public class SavingsAccountData { account.overdraftLimit, account.minRequiredBalance, account.enforceMinRequiredBalance, account.minBalanceForInterestCalculation, account.onHoldFunds, account.nominalAnnualInterestRateOverdraft, account.minOverdraftForInterestCalculation, account.withHoldTax, account.taxGroup, account.lastActiveTransactionDate, - account.isDormancyTrackingActive, account.daysToInactive, account.daysToDormancy, account.daysToEscheat); + account.isDormancyTrackingActive, account.daysToInactive, account.daysToDormancy, account.daysToEscheat, account.savingsAmountOnHold); } public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId, @@ -407,6 +410,7 @@ public class SavingsAccountData { final Integer daysToInactive = null; final Integer daysToDormancy = null; final Integer daysToEscheat = null; + final BigDecimal savingsAmountOnHold = null; return new SavingsAccountData(id, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualInterestRate, @@ -417,7 +421,7 @@ public class SavingsAccountData { lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, - lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat); + lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold); } private SavingsAccountData(final Long id, final String accountNo, final EnumOptionData depositType, final String externalId, @@ -441,7 +445,7 @@ public class SavingsAccountData { final BigDecimal onHoldFunds, final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation, final boolean withHoldTax, final TaxGroupData taxGroup, final LocalDate lastActiveTransactionDate, final boolean isDormancyTrackingActive, final Integer daysToInactive, - final Integer daysToDormancy, final Integer daysToEscheat) { + final Integer daysToDormancy, final Integer daysToEscheat, final BigDecimal savingsAmountOnHold) { this.id = id; this.accountNo = accountNo; this.depositType = depositType; @@ -507,6 +511,7 @@ public class SavingsAccountData { this.daysToInactive = daysToInactive; this.daysToDormancy = daysToDormancy; this.daysToEscheat = daysToEscheat; + this.savingsAmountOnHold = savingsAmountOnHold; } private SavingsAccountChargeData getWithdrawalFee() { http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java index fcd7a88..02ae102 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java @@ -121,7 +121,7 @@ public class SavingsAccountTransactionDataValidator { throwExceptionIfValidationWarningsExist(dataValidationErrors); } - public void validateClosing(final JsonCommand command) { + public void validateClosing(final JsonCommand command, final SavingsAccount account) { final String json = command.json(); if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } @@ -144,6 +144,11 @@ public class SavingsAccountTransactionDataValidator { baseDataValidator.reset().parameter(withdrawBalanceParamName).value(withdrawBalance).isOneOfTheseValues(true, false); } + if (account.getSavingsHoldAmount().compareTo(BigDecimal.ZERO) == 1) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( + "amount.is.on.hold.release.the.amount.to.continue", account.getId()); + } + validatePaymentTypeDetails(baseDataValidator, element); throwExceptionIfValidationWarningsExist(dataValidationErrors); @@ -192,10 +197,9 @@ public class SavingsAccountTransactionDataValidator { baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName) .failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE); } - account.holdFunds(amount); - if (account.getWithdrawableBalance().compareTo(BigDecimal.ZERO) == -1) { + account.holdAmount(amount); + if (account.getWithdrawableBalance().compareTo(BigDecimal.ZERO)==-1){ baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId()); - baseDataValidator.failWithCode("validation.msg.savingsaccount.insufficient balance", "Insufficient balance"); } LocalDate lastTransactionDate = account.retrieveLastTransactionDate(); // compare two dates now @@ -206,7 +210,8 @@ public class SavingsAccountTransactionDataValidator { throwExceptionIfValidationWarningsExist(dataValidationErrors); final PaymentDetail paymentDetails = null; - Date createdDate = DateUtils.getDateOfTenant(); + Date createdDate = new Date(); + SavingsAccountTransaction transaction = SavingsAccountTransaction.holdAmount(account, account.office(), paymentDetails, transactionDate, Money.of(account.getCurrency(), amount), createdDate, createdUser); return transaction; @@ -217,15 +222,24 @@ public class SavingsAccountTransactionDataValidator { final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) .resource(SAVINGS_ACCOUNT_RESOURCE_NAME); - if (holdTransaction == null) { - baseDataValidator.failWithCode("validation.msg.validation.errors.exist", "Transaction not found"); - } else if (holdTransaction.getReleaseIdOfHoldAmountTransaction() != null) { - baseDataValidator.parameter(SavingsApiConstants.amountParamName).value(holdTransaction.getAmount()).failWithCode("validation.msg.amount.is.not.on.hold", - "Transaction amount is not on hold"); - } + if (holdTransaction == null) { + baseDataValidator.failWithCode("validation.msg.validation.errors.exist", "Transaction not found"); + } else if (holdTransaction.getReleaseIdOfHoldAmountTransaction() != null) { + baseDataValidator.parameter(SavingsApiConstants.amountParamName).value(holdTransaction.getAmount()) + .failWithCode("validation.msg.amount.is.not.on.hold", "Transaction amount is not on hold"); + } + + if (holdTransaction != null) { + boolean isActive = holdTransaction.getSavingsAccount().isActive(); + if (!isActive) { + baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName) + .failWithCodeNoParameterAddedToErrorCode( + SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE); + } + } throwExceptionIfValidationWarningsExist(dataValidationErrors); - Date createdDate = DateUtils.getDateOfTenant(); + Date createdDate = new Date(); LocalDate transactionDate = DateUtils.getLocalDateOfTenant(); SavingsAccountTransaction transaction = SavingsAccountTransaction.releaseAmount(holdTransaction, transactionDate, createdDate, createdUser); http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java index f904b09..0acd096 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java @@ -325,6 +325,8 @@ public class SavingsAccount extends AbstractPersistableCustom<Long> { @JoinColumn(name = "tax_group_id") private TaxGroup taxGroup; + @Column(name = "total_savings_amount_on_hold", scale = 6, precision = 19, nullable = true) + private BigDecimal savingsOnHoldAmount; protected SavingsAccount() { // } @@ -1051,19 +1053,16 @@ public class SavingsAccount extends AbstractPersistableCustom<Long> { Money runningBalance = Money.zero(this.currency); Money minRequiredBalance = minRequiredBalanceDerived(getCurrency()); LocalDate lastSavingsDate = null; + final BigDecimal withdrawalFee = null; for (final SavingsAccountTransaction transaction : transactionsSortedByDate) { if (transaction.isNotReversed() && transaction.isCredit()) { runningBalance = runningBalance.plus(transaction.getAmount(this.currency)); } else if (transaction.isNotReversed() && transaction.isDebit()) { runningBalance = runningBalance.minus(transaction.getAmount(this.currency)); - } else if(transaction.isAmountOnHold() && transaction.getReleaseIdOfHoldAmountTransaction() == null){ - runningBalance = runningBalance.minus(transaction.getAmount(this.currency)); }else { continue; } - final BigDecimal withdrawalFee = null; - /* * Loop through the onHold funds and see if we need to deduct or add * to minimum required balance and the point in time the transaction @@ -1093,6 +1092,12 @@ public class SavingsAccount extends AbstractPersistableCustom<Long> { lastSavingsDate = transaction.transactionLocalDate(); } + if (this.getSavingsHoldAmount().compareTo(BigDecimal.ZERO) == 1) { + if (runningBalance.minus(this.getSavingsHoldAmount()).isLessThanZero()) { + throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), withdrawalFee, + transactionAmount); + } + } } public void validateAccountBalanceDoesNotBecomeNegative(final String transactionAction, @@ -2753,7 +2758,7 @@ public class SavingsAccount extends AbstractPersistableCustom<Long> { } public BigDecimal getWithdrawableBalance() { - return getAccountBalance().subtract(minRequiredBalanceDerived(getCurrency()).getAmount()).subtract(this.getOnHoldFunds()); + return getAccountBalance().subtract(minRequiredBalanceDerived(getCurrency()).getAmount()).subtract(this.getOnHoldFunds()).subtract(this.getSavingsHoldAmount()); } public TaxGroup getTaxGroup() { @@ -3006,9 +3011,27 @@ public class SavingsAccount extends AbstractPersistableCustom<Long> { public LocalDate retrieveLastTransactionDate() { final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions(); - SavingsAccountTransaction lastTransaction = transactionsSortedByDate.get(transactionsSortedByDate.size() - 1); - return lastTransaction.transactionLocalDate(); + SavingsAccountTransaction lastTransaction = null; + if (transactionsSortedByDate.size() > 0) { + lastTransaction = transactionsSortedByDate.get(transactionsSortedByDate.size() - 1); + } + LocalDate lastransactionDate = null; + if (lastTransaction != null) { + lastransactionDate = lastTransaction.transactionLocalDate(); + } + return lastransactionDate; } - - + + public BigDecimal getSavingsHoldAmount() { + return this.savingsOnHoldAmount == null ? BigDecimal.ZERO : this.savingsOnHoldAmount; + } + + public void holdAmount(BigDecimal amount) { + this.savingsOnHoldAmount = getSavingsHoldAmount().add(amount); + } + + public void releaseAmount(BigDecimal amount) { + this.savingsOnHoldAmount = getSavingsHoldAmount().subtract(amount); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java index 12de527..cf5ae03 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java @@ -787,4 +787,8 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom<L public Long getReleaseIdOfHoldAmountTransaction() { return this.releaseIdOfHoldAmountTransaction; } + + public boolean isAmountOnHoldNotReleased() { + return (isAmountOnHold() && getReleaseIdOfHoldAmountTransaction() == null); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index 1b68e3f..a9704eb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -304,6 +304,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("sa.withhold_tax as withHoldTax, "); sqlBuilder.append("sa.total_withhold_tax_derived as totalWithholdTax, "); sqlBuilder.append("sa.last_interest_calculation_date as lastInterestCalculationDate, "); + sqlBuilder.append("sa.total_savings_amount_on_hold as onHoldAmount, "); sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, "); sqlBuilder.append("(select IFNULL(max(sat.transaction_date),sa.activatedon_date) "); sqlBuilder.append("from m_savings_account_transaction as sat "); @@ -511,12 +512,19 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead "minBalanceForInterestCalculation"); final BigDecimal onHoldFunds = rs.getBigDecimal("onHoldFunds"); + final BigDecimal onHoldAmount = rs.getBigDecimal("onHoldAmount"); + BigDecimal availableBalance = accountBalance; if (availableBalance != null && onHoldFunds != null) { availableBalance = availableBalance.subtract(onHoldFunds); } + if (availableBalance != null && onHoldAmount != null) { + + availableBalance = availableBalance.subtract(onHoldAmount); + } + BigDecimal interestNotPosted = BigDecimal.ZERO; LocalDate lastInterestCalculationDate = null; if(totalInterestEarned != null){ @@ -542,7 +550,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, - taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat); + taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, onHoldAmount); } } @@ -1074,7 +1082,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead // final LocalDate annualFeeNextDueDate = null; final SavingsAccountSummaryData summary = null; final BigDecimal onHoldFunds = null; - + final BigDecimal savingsAmountOnHold = null; + final SavingsAccountSubStatusEnumData subStatus = null; final LocalDate lastActiveTransactionDate = null; final boolean isDormancyTrackingActive = false; @@ -1090,7 +1099,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, - taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat); + taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold); } } http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index f9e52b2..03409ed 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -612,8 +612,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi public CommandProcessingResult close(final Long savingsId, final JsonCommand command) { final AppUser user = this.context.authenticatedUser(); - this.savingsAccountTransactionDataValidator.validateClosing(command); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); + this.savingsAccountTransactionDataValidator.validateClosing(command, account); + final boolean isLinkedWithAnyActiveLoan = this.accountAssociationsReadPlatformService.isLinkedWithAnyActiveAccount(savingsId); if (isLinkedWithAnyActiveLoan) { @@ -1403,7 +1404,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi .validateReleaseAmountAndAssembleForm(holdTransaction, submittedBy); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(account); - account.releaseFunds(transaction.getAmount()); + account.releaseAmount(transaction.getAmount()); this.savingsAccountTransactionRepository.save(transaction); holdTransaction.updateReleaseId(transaction.getId()); http://git-wip-us.apache.org/repos/asf/fineract/blob/7368c3f1/fineract-provider/src/main/resources/sql/migrations/core_db/V330__savings_account_transaction_releaseId.sql ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V330__savings_account_transaction_releaseId.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V330__savings_account_transaction_releaseId.sql index cf9e24c..c20ea9f 100644 --- a/fineract-provider/src/main/resources/sql/migrations/core_db/V330__savings_account_transaction_releaseId.sql +++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V330__savings_account_transaction_releaseId.sql @@ -40,5 +40,9 @@ INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `c ALTER TABLE `m_savings_account_transaction` ADD COLUMN `release_id_of_hold_amount` BIGINT(20) NULL DEFAULT NULL; +-- modify `m_savings_account` + +ALTER TABLE `m_savings_account` ADD COLUMN `total_savings_amount_on_hold` DECIMAL(19,6) NULL DEFAULT NULL; +