Merge pull request #933 from lingalamadhukar/MIFOSX-1267

MIFOSX-1260,MIFOSX-1287,MIFOSX-1311
This commit is contained in:
Vishwas Babu A J
2014-06-10 07:55:38 -07:00
9 changed files with 75 additions and 49 deletions
@@ -975,6 +975,7 @@ public class RecurringDepositTest {
DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE); DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE);
Assert.assertNotNull(transactionIdForDeposit); Assert.assertNotNull(transactionIdForDeposit);
currentDate = currentDate - 1;
interestPerMonth = (float) (interestPerDay * principal * currentDate); interestPerMonth = (float) (interestPerDay * principal * currentDate);
System.out.println("IPM = " + interestPerMonth); System.out.println("IPM = " + interestPerMonth);
principal += interestPerMonth; principal += interestPerMonth;
@@ -1101,6 +1102,7 @@ public class RecurringDepositTest {
DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE); DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE);
Assert.assertNotNull(transactionIdForDeposit); Assert.assertNotNull(transactionIdForDeposit);
currentDate = currentDate - 1;
interestPerMonth = (float) (interestPerDay * principal * currentDate); interestPerMonth = (float) (interestPerDay * principal * currentDate);
System.out.println("IPM = " + interestPerMonth); System.out.println("IPM = " + interestPerMonth);
principal += interestPerMonth; principal += interestPerMonth;
@@ -1230,6 +1232,7 @@ public class RecurringDepositTest {
DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE); DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE);
Assert.assertNotNull(transactionIdForDeposit); Assert.assertNotNull(transactionIdForDeposit);
currentDate = currentDate - 1;
interestPerMonth = (float) (interestPerDay * principal * currentDate); interestPerMonth = (float) (interestPerDay * principal * currentDate);
System.out.println("IPM = " + interestPerMonth); System.out.println("IPM = " + interestPerMonth);
principal += interestPerMonth; principal += interestPerMonth;
@@ -1364,6 +1367,7 @@ public class RecurringDepositTest {
DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE); DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE);
Assert.assertNotNull(newTransactionIdForDeposit); Assert.assertNotNull(newTransactionIdForDeposit);
currentDate = currentDate - 1;
interestPerMonth = (float) (interestPerDay * principal * currentDate); interestPerMonth = (float) (interestPerDay * principal * currentDate);
System.out.println("IPM = " + interestPerMonth); System.out.println("IPM = " + interestPerMonth);
principal += interestPerMonth; principal += interestPerMonth;
@@ -148,7 +148,7 @@ public class InterestRateChartSlabDataValidator {
if (this.fromApiJsonHelper.parameterExists(descriptionParamName, element)) { if (this.fromApiJsonHelper.parameterExists(descriptionParamName, element)) {
final String description = this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element); final String description = this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
baseDataValidator.reset().parameter(descriptionParamName).value(description).notNull(); baseDataValidator.reset().parameter(descriptionParamName).value(description).ignoreIfNull();
} }
if (this.fromApiJsonHelper.parameterExists(periodTypeParamName, element)) { if (this.fromApiJsonHelper.parameterExists(periodTypeParamName, element)) {
@@ -117,12 +117,13 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount account, final DateTimeFormatter fmt, public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) { final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) {
boolean isAccountTransfer = false; boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate,
transactionAmount, paymentDetail, isAccountTransfer); transactionAmount, paymentDetail, isAccountTransfer);
account.handleScheduleInstallments(deposit); account.handleScheduleInstallments(deposit);
account.updateMaturityDateAndAmount(mc); account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
account.updateOverduePayments(DateUtils.getLocalDateOfTenant()); account.updateOverduePayments(DateUtils.getLocalDateOfTenant());
return deposit; return deposit;
} }
@@ -132,6 +133,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
public Long handleFDAccountClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, public Long handleFDAccountClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) { final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
boolean isAccountTransfer = false; boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
final Set<Long> existingTransactionIds = new HashSet<Long>(); final Set<Long> existingTransactionIds = new HashSet<Long>();
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
@@ -157,7 +159,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
if (account.isReinvestOnClosure()) { if (account.isReinvestOnClosure()) {
FixedDepositAccount reinvestedDeposit = account.reInvest(account.getAccountBalance()); FixedDepositAccount reinvestedDeposit = account.reInvest(account.getAccountBalance());
this.depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit); this.depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
reinvestedDeposit.updateMaturityDateAndAmountBeforeAccountActivation(mc); reinvestedDeposit.updateMaturityDateAndAmountBeforeAccountActivation(mc,isPreMatureClosure);
this.savingsAccountRepository.save(reinvestedDeposit); this.savingsAccountRepository.save(reinvestedDeposit);
autoGenerateAccountNumber(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit);
final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(),
@@ -192,6 +194,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
public Long handleRDAccountClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, public Long handleRDAccountClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) { final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
boolean isAccountTransfer = false; boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
final Set<Long> existingTransactionIds = new HashSet<Long>(); final Set<Long> existingTransactionIds = new HashSet<Long>();
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
@@ -206,9 +209,9 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
if (account.isReinvestOnClosure()) { if (account.isReinvestOnClosure()) {
RecurringDepositAccount reinvestedDeposit = account.reInvest(transactionAmount); RecurringDepositAccount reinvestedDeposit = account.reInvest(transactionAmount);
depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit); depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
reinvestedDeposit.updateMaturityDateAndAmount(mc); reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure);
reinvestedDeposit.processAccountUponActivation(fmt); reinvestedDeposit.processAccountUponActivation(fmt);
reinvestedDeposit.updateMaturityDateAndAmount(mc); reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure);
this.savingsAccountRepository.save(reinvestedDeposit); this.savingsAccountRepository.save(reinvestedDeposit);
Money amountForDeposit = reinvestedDeposit.activateWithBalance(); Money amountForDeposit = reinvestedDeposit.activateWithBalance();
@@ -216,7 +219,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
handleRDDeposit(reinvestedDeposit, fmt, reinvestedDeposit.getActivationLocalDate(), amountForDeposit.getAmount(), handleRDDeposit(reinvestedDeposit, fmt, reinvestedDeposit.getActivationLocalDate(), amountForDeposit.getAmount(),
paymentDetail); paymentDetail);
} }
reinvestedDeposit.updateMaturityDateAndAmount(mc); reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure);
this.savingsAccountRepository.save(reinvestedDeposit); this.savingsAccountRepository.save(reinvestedDeposit);
autoGenerateAccountNumber(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit);
@@ -263,6 +266,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) { final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
boolean isAccountTransfer = false; boolean isAccountTransfer = false;
final boolean isPreMatureClosure = true;
final Set<Long> existingTransactionIds = new HashSet<Long>(); final Set<Long> existingTransactionIds = new HashSet<Long>();
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
@@ -272,7 +276,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
Long savingsTransactionId = null; Long savingsTransactionId = null;
// post interest // post interest
account.postPreMaturityInterest(closedDate); account.postPreMaturityInterest(closedDate, isPreMatureClosure);
final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName); final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName);
DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue); DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue);
@@ -306,6 +310,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail,
final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) { final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
boolean isAccountTransfer = false; boolean isAccountTransfer = false;
final boolean isPreMatureClosure = true;
final Set<Long> existingTransactionIds = new HashSet<Long>(); final Set<Long> existingTransactionIds = new HashSet<Long>();
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
@@ -315,7 +320,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
Long savingsTransactionId = null; Long savingsTransactionId = null;
// post interest // post interest
account.postPreMaturityInterest(closedDate); account.postPreMaturityInterest(closedDate, isPreMatureClosure);
final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName); final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName);
DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue); DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue);
@@ -131,14 +131,13 @@ public class FixedDepositAccount extends SavingsAccount {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
@Override protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate interestPostingUpToDate,
protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate interestPostingUpToDate) { final boolean isPreMatureClosure) {
// default it to nominalAnnualInterst rate. interest chart overrrides // default it to nominalAnnualInterst rate. interest chart overrrides
// this value. // this value.
BigDecimal applicableInterestRate = this.nominalAnnualInterestRate; BigDecimal applicableInterestRate = this.nominalAnnualInterestRate;
if (this.chart != null) { if (this.chart != null) {
final boolean isPreMatureClosure = SavingsAccountStatusType.fromInt(this.status).isPreMatureClosure();
boolean applyPreMaturePenalty = false; boolean applyPreMaturePenalty = false;
BigDecimal penalInterest = BigDecimal.ZERO; BigDecimal penalInterest = BigDecimal.ZERO;
LocalDate depositCloseDate = calculateMaturityDate(); LocalDate depositCloseDate = calculateMaturityDate();
@@ -170,7 +169,7 @@ public class FixedDepositAccount extends SavingsAccount {
return applicableInterestRate.divide(BigDecimal.valueOf(100l), mc); return applicableInterestRate.divide(BigDecimal.valueOf(100l), mc);
} }
public void updateMaturityDateAndAmountBeforeAccountActivation(final MathContext mc) { public void updateMaturityDateAndAmountBeforeAccountActivation(final MathContext mc, final boolean isPreMatureClosure) {
List<SavingsAccountTransaction> allTransactions = new ArrayList<SavingsAccountTransaction>(); List<SavingsAccountTransaction> allTransactions = new ArrayList<SavingsAccountTransaction>();
final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount()); final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount());
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null,
@@ -178,14 +177,15 @@ public class FixedDepositAccount extends SavingsAccount {
transaction.updateRunningBalance(transactionAmountMoney); transaction.updateRunningBalance(transactionAmountMoney);
transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto()); transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto());
allTransactions.add(transaction); allTransactions.add(transaction);
updateMaturityDateAndAmount(mc, allTransactions); updateMaturityDateAndAmount(mc, allTransactions, isPreMatureClosure);
} }
public void updateMaturityDateAndAmount(final MathContext mc) { public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure) {
updateMaturityDateAndAmount(mc, retreiveOrderedNonInterestPostingTransactions()); updateMaturityDateAndAmount(mc, retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure);
} }
public void updateMaturityDateAndAmount(final MathContext mc, final List<SavingsAccountTransaction> transactions) { public void updateMaturityDateAndAmount(final MathContext mc, final List<SavingsAccountTransaction> transactions,
final boolean isPreMatureClosure) {
final LocalDate maturityDate = calculateMaturityDate(); final LocalDate maturityDate = calculateMaturityDate();
final LocalDate interestCalculationUpto = maturityDate.minusDays(1); final LocalDate interestCalculationUpto = maturityDate.minusDays(1);
@@ -193,7 +193,7 @@ public class FixedDepositAccount extends SavingsAccount {
// calculation // calculation
this.resetAccountTransactionsEndOfDayBalances(transactions, maturityDate); this.resetAccountTransactionsEndOfDayBalances(transactions, maturityDate);
final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, transactions); final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, transactions, isPreMatureClosure);
// reset end of day balance back to today's date // reset end of day balance back to today's date
this.resetAccountTransactionsEndOfDayBalances(transactions, DateUtils.getLocalDateOfTenant()); this.resetAccountTransactionsEndOfDayBalances(transactions, DateUtils.getLocalDateOfTenant());
@@ -253,7 +253,7 @@ public class FixedDepositAccount extends SavingsAccount {
} }
private List<PostingPeriod> calculateInterestPayable(final MathContext mc, final LocalDate maturityDate, private List<PostingPeriod> calculateInterestPayable(final MathContext mc, final LocalDate maturityDate,
final List<SavingsAccountTransaction> transactions) { final List<SavingsAccountTransaction> transactions, final boolean isPreMatureClosure) {
final SavingsPostingInterestPeriodType postingPeriodType = SavingsPostingInterestPeriodType.fromInt(this.interestPostingPeriodType); final SavingsPostingInterestPeriodType postingPeriodType = SavingsPostingInterestPeriodType.fromInt(this.interestPostingPeriodType);
@@ -271,7 +271,7 @@ public class FixedDepositAccount extends SavingsAccount {
Money periodStartingBalance = Money.zero(currency); Money periodStartingBalance = Money.zero(currency);
final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType); final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType);
final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate); final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate, isPreMatureClosure);
final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId()); final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId());
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
for (final LocalDateInterval periodInterval : postingPeriodIntervals) { for (final LocalDateInterval periodInterval : postingPeriodIntervals) {
@@ -496,10 +496,10 @@ public class FixedDepositAccount extends SavingsAccount {
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
} }
public void postPreMaturityInterest(final LocalDate accountCloseDate) { public void postPreMaturityInterest(final LocalDate accountCloseDate, final boolean isPreMatureClosure) {
Money interestPostedToDate = totalInterestPosted(); Money interestPostedToDate = totalInterestPosted();
final Money interestOnMaturity = calculatePreMatureInterest(accountCloseDate, retreiveOrderedNonInterestPostingTransactions()); final Money interestOnMaturity = calculatePreMatureInterest(accountCloseDate, retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure);
boolean recalucateDailyBalance = false; boolean recalucateDailyBalance = false;
// post remaining interest // post remaining interest
@@ -521,11 +521,12 @@ public class FixedDepositAccount extends SavingsAccount {
} }
public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate) { public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate, final boolean isPreMatureClosure) {
final Money interestPostedToDate = totalInterestPosted().copy(); final Money interestPostedToDate = totalInterestPosted().copy();
final Money interestEarnedTillDate = calculatePreMatureInterest(preMatureDate, retreiveOrderedNonInterestPostingTransactions()); final Money interestEarnedTillDate = calculatePreMatureInterest(preMatureDate, retreiveOrderedNonInterestPostingTransactions(),
isPreMatureClosure);
final Money accountBalance = Money.of(getCurrency(), getAccountBalance()); final Money accountBalance = Money.of(getCurrency(), getAccountBalance());
final Money maturityAmount = accountBalance.minus(interestPostedToDate).plus(interestEarnedTillDate); final Money maturityAmount = accountBalance.minus(interestPostedToDate).plus(interestEarnedTillDate);
@@ -533,9 +534,10 @@ public class FixedDepositAccount extends SavingsAccount {
return maturityAmount.getAmount(); return maturityAmount.getAmount();
} }
private Money calculatePreMatureInterest(final LocalDate preMatureDate, final List<SavingsAccountTransaction> transactions) { private Money calculatePreMatureInterest(final LocalDate preMatureDate, final List<SavingsAccountTransaction> transactions,
final boolean isPreMatureClosure) {
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions); final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions, isPreMatureClosure);
Money interestOnMaturity = Money.zero(this.currency); Money interestOnMaturity = Money.zero(this.currency);
@@ -164,10 +164,9 @@ public class RecurringDepositAccount extends SavingsAccount {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
@Override protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate interestPostingUpToDate,
protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate interestPostingUpToDate) { final boolean isPreMatureClosure) {
final boolean isPreMatureClosure = SavingsAccountStatusType.fromInt(this.status).isPreMatureClosure();
boolean applyPreMaturePenalty = false; boolean applyPreMaturePenalty = false;
BigDecimal penalInterest = BigDecimal.ZERO; BigDecimal penalInterest = BigDecimal.ZERO;
LocalDate depositCloseDate = calculateMaturityDate(); LocalDate depositCloseDate = calculateMaturityDate();
@@ -199,12 +198,13 @@ public class RecurringDepositAccount extends SavingsAccount {
return applicableInterestRate.divide(BigDecimal.valueOf(100l), mc); return applicableInterestRate.divide(BigDecimal.valueOf(100l), mc);
} }
public void updateMaturityDateAndAmount(final MathContext mc) { public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure) {
final LocalDate maturityDate = calculateMaturityDate(); final LocalDate maturityDate = calculateMaturityDate();
final LocalDate interestCalculationUpto = maturityDate.minusDays(1); final LocalDate interestCalculationUpto = maturityDate.minusDays(1);
final List<SavingsAccountTransaction> allTransactions = generateIncludingFutureTransactions(interestCalculationUpto); final List<SavingsAccountTransaction> allTransactions = generateIncludingFutureTransactions(interestCalculationUpto);
final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, allTransactions); final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, allTransactions,
isPreMatureClosure);
Money totalInterestPayable = Money.zero(getCurrency()); Money totalInterestPayable = Money.zero(getCurrency());
Money totalDepositAmount = Money.zero(getCurrency()); Money totalDepositAmount = Money.zero(getCurrency());
for (PostingPeriod postingPeriod : postingPeriods) { for (PostingPeriod postingPeriod : postingPeriods) {
@@ -260,7 +260,7 @@ public class RecurringDepositAccount extends SavingsAccount {
} }
private List<PostingPeriod> calculateInterestPayable(final MathContext mc, final LocalDate maturityDate, private List<PostingPeriod> calculateInterestPayable(final MathContext mc, final LocalDate maturityDate,
final List<SavingsAccountTransaction> transactions) { final List<SavingsAccountTransaction> transactions, final boolean isPreMatureClosure) {
// 1. default to calculate interest based on entire history OR // 1. default to calculate interest based on entire history OR
// 2. determine latest 'posting period' and find interest credited to // 2. determine latest 'posting period' and find interest credited to
@@ -283,7 +283,7 @@ public class RecurringDepositAccount extends SavingsAccount {
Money periodStartingBalance = Money.zero(currency); Money periodStartingBalance = Money.zero(currency);
final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType); final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType);
final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate); final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate, isPreMatureClosure);
final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId()); final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId());
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
for (final LocalDateInterval periodInterval : postingPeriodIntervals) { for (final LocalDateInterval periodInterval : postingPeriodIntervals) {
@@ -597,10 +597,10 @@ public class RecurringDepositAccount extends SavingsAccount {
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
} }
public void postPreMaturityInterest(final LocalDate accountCloseDate) { public void postPreMaturityInterest(final LocalDate accountCloseDate, final boolean isPreMatureClosure) {
final Money interestPostedToDate = totalInterestPosted(); final Money interestPostedToDate = totalInterestPosted();
final Money interestOnMaturity = calculatePreMatureInterest(accountCloseDate, retreiveOrderedNonInterestPostingTransactions()); final Money interestOnMaturity = calculatePreMatureInterest(accountCloseDate, retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure);
boolean recalucateDailyBalance = false; boolean recalucateDailyBalance = false;
@@ -623,11 +623,12 @@ public class RecurringDepositAccount extends SavingsAccount {
this.accountTermAndPreClosure.updateMaturityDetails(this.getAccountBalance(), accountCloseDate); this.accountTermAndPreClosure.updateMaturityDetails(this.getAccountBalance(), accountCloseDate);
} }
public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate) { public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate, final boolean isPreMatureClosure) {
final Money interestPostedToDate = totalInterestPosted().copy(); final Money interestPostedToDate = totalInterestPosted().copy();
final Money interestEarnedTillDate = calculatePreMatureInterest(preMatureDate, retreiveOrderedNonInterestPostingTransactions()); final Money interestEarnedTillDate = calculatePreMatureInterest(preMatureDate, retreiveOrderedNonInterestPostingTransactions(),
isPreMatureClosure);
final Money accountBalance = Money.of(getCurrency(), getAccountBalance()); final Money accountBalance = Money.of(getCurrency(), getAccountBalance());
final Money maturityAmount = accountBalance.minus(interestPostedToDate).plus(interestEarnedTillDate); final Money maturityAmount = accountBalance.minus(interestPostedToDate).plus(interestEarnedTillDate);
@@ -635,9 +636,10 @@ public class RecurringDepositAccount extends SavingsAccount {
return maturityAmount.getAmount(); return maturityAmount.getAmount();
} }
private Money calculatePreMatureInterest(final LocalDate preMatureDate, final List<SavingsAccountTransaction> transactions) { private Money calculatePreMatureInterest(final LocalDate preMatureDate, final List<SavingsAccountTransaction> transactions,
final boolean isPreMatureClosure) {
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions); final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions, isPreMatureClosure);
Money interestOnMaturity = Money.zero(this.currency); Money interestOnMaturity = Money.zero(this.currency);
@@ -71,15 +71,18 @@ public class DepositAccountPreMatureCalculationPlatformServiceImpl implements De
account.clientId(), DepositAccountType.SAVINGS_DEPOSIT); account.clientId(), DepositAccountType.SAVINGS_DEPOSIT);
final JsonElement element = this.fromJsonHelper.parse(query.json()); final JsonElement element = this.fromJsonHelper.parse(query.json());
final LocalDate preMaturityDate = this.fromJsonHelper.extractLocalDateNamed(closedOnDateParamName, element); final LocalDate preMaturityDate = this.fromJsonHelper.extractLocalDateNamed(closedOnDateParamName, element);
final boolean isPreMatureClosure = true;
if (depositAccountType.isFixedDeposit()) { if (depositAccountType.isFixedDeposit()) {
final FixedDepositAccount fd = (FixedDepositAccount) account; final FixedDepositAccount fd = (FixedDepositAccount) account;
accountData = FixedDepositAccountData.preClosureDetails(account.getId(), fd.calculatePreMatureAmount(preMaturityDate), accountData = FixedDepositAccountData.preClosureDetails(account.getId(),
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas); fd.calculatePreMatureAmount(preMaturityDate, isPreMatureClosure), onAccountClosureOptions, paymentTypeOptions,
savingsAccountDatas);
} else if (depositAccountType.isRecurringDeposit()) { } else if (depositAccountType.isRecurringDeposit()) {
final RecurringDepositAccount rd = (RecurringDepositAccount) account; final RecurringDepositAccount rd = (RecurringDepositAccount) account;
accountData = RecurringDepositAccountData.preClosureDetails(account.getId(), rd.calculatePreMatureAmount(preMaturityDate), accountData = RecurringDepositAccountData.preClosureDetails(account.getId(),
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas); rd.calculatePreMatureAmount(preMaturityDate, isPreMatureClosure), onAccountClosureOptions, paymentTypeOptions,
savingsAccountDatas);
} }
return accountData; return accountData;
@@ -215,7 +215,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
} }
account.updateMaturityDateAndAmount(mc); final boolean isPreMatureClosure = false;
account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name()); account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name());
this.savingAccountRepository.save(account); this.savingAccountRepository.save(account);
} }
@@ -276,6 +277,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
// submitted and activation date are different then recalculate // submitted and activation date are different then recalculate
// maturity date and schedule // maturity date and schedule
if (!account.accountSubmittedAndActivationOnSameDate()) { if (!account.accountSubmittedAndActivationOnSameDate()) {
final boolean isPreMatureClosure = false;
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId( final CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
savingsId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue()); savingsId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
@@ -284,7 +286,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence()); Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence());
frequency = frequency == -1 ? 1 : frequency; frequency = frequency == -1 ? 1 : frequency;
account.generateSchedule(frequencyType, frequency); account.generateSchedule(frequencyType, frequency);
account.updateMaturityDateAndAmount(mc); account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
} }
final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils
@@ -517,7 +519,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
} }
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction); account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction);
// account.activateAccountBasedOnBalance(); // account.activateAccountBasedOnBalance();
account.updateMaturityDateAndAmount(mc); final boolean isPreMatureClosure = false;
account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils
.getLocalDateOfTenant() : account.maturityDate(); .getLocalDateOfTenant() : account.maturityDate();
@@ -172,8 +172,9 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
DepositAccountType.FIXED_DEPOSIT); DepositAccountType.FIXED_DEPOSIT);
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
final boolean isPreMatureClosure = false;
account.updateMaturityDateAndAmountBeforeAccountActivation(mc); account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure);
this.fixedDepositAccountRepository.save(account); this.fixedDepositAccountRepository.save(account);
if (account.isAccountNumberRequiresAutoGeneration()) { if (account.isAccountNumberRequiresAutoGeneration()) {
@@ -240,7 +241,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence()); Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence());
frequency = frequency == -1 ? 1 : frequency; frequency = frequency == -1 ? 1 : frequency;
account.generateSchedule(frequencyType, frequency); account.generateSchedule(frequencyType, frequency);
account.updateMaturityDateAndAmount(mc); final boolean isPreMatureClosure = false;
account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
account.validateApplicableInterestRate(); account.validateApplicableInterestRate();
this.savingAccountRepository.save(account); this.savingAccountRepository.save(account);
@@ -328,7 +330,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
updateFDAndRDCommonChanges(changes, command, account); updateFDAndRDCommonChanges(changes, command, account);
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
account.updateMaturityDateAndAmountBeforeAccountActivation(mc); final boolean isPreMatureClosure = false;
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure);
this.savingAccountRepository.save(account); this.savingAccountRepository.save(account);
} }
@@ -371,7 +374,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence()); Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence());
frequency = frequency == -1 ? 1 : frequency; frequency = frequency == -1 ? 1 : frequency;
account.generateSchedule(frequencyType, frequency); account.generateSchedule(frequencyType, frequency);
account.updateMaturityDateAndAmount(mc); final boolean isPreMatureClosure = false;
account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
account.validateApplicableInterestRate(); account.validateApplicableInterestRate();
this.savingAccountRepository.save(account); this.savingAccountRepository.save(account);
@@ -453,6 +453,9 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
Money amountForDeposit = account.activateWithBalance(); Money amountForDeposit = account.activateWithBalance();
boolean isAccountTransfer = false; boolean isAccountTransfer = false;
if (amountForDeposit.isGreaterThanZero()) { if (amountForDeposit.isGreaterThanZero()) {
// save account entity before performing deposit transaction, as
// accountId is required for persist transaction entity.
this.savingAccountRepository.save(account);
this.savingsAccountDomainService.handleDeposit(account, savingsAccountDataDTO.getFmt(), account.getActivationLocalDate(), this.savingsAccountDomainService.handleDeposit(account, savingsAccountDataDTO.getFmt(), account.getActivationLocalDate(),
amountForDeposit.getAmount(), null, isAccountTransfer); amountForDeposit.getAmount(), null, isAccountTransfer);
} }