MIFOSX-1850 : Recurring deposits without maturity date
This commit is contained in:
+2
-1
@@ -23,7 +23,8 @@ public enum JobName {
|
|||||||
UPDATE_DEPOSITS_ACCOUNT_MATURITY_DETAILS("Update Deposit Accounts Maturity details"),
|
UPDATE_DEPOSITS_ACCOUNT_MATURITY_DETAILS("Update Deposit Accounts Maturity details"),
|
||||||
TRANSFER_INTEREST_TO_SAVINGS("Transfer Interest To Savings"),
|
TRANSFER_INTEREST_TO_SAVINGS("Transfer Interest To Savings"),
|
||||||
ADD_PERIODIC_ACCRUAL_ENTRIES("Add Periodic Accrual Transactions"),
|
ADD_PERIODIC_ACCRUAL_ENTRIES("Add Periodic Accrual Transactions"),
|
||||||
RECALCULATE_INTEREST_FOR_LOAN("Recalculate Interest For Loans");
|
RECALCULATE_INTEREST_FOR_LOAN("Recalculate Interest For Loans"),
|
||||||
|
GENERATE_RD_SCEHDULE("Generate Mandatory Savings Schedule");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
|||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.savings;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
||||||
|
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||||
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
|
||||||
|
public class DepositAccountUtils {
|
||||||
|
|
||||||
|
public static final int GENERATE_MINIMUM_NUMBER_OF_FUTURE_INSTALMENTS = 5;
|
||||||
|
|
||||||
|
public static LocalDate calculateNextDepositDate(final LocalDate lastDepositDate, final PeriodFrequencyType frequency,
|
||||||
|
final int recurringEvery) {
|
||||||
|
LocalDate nextDepositDate = lastDepositDate;
|
||||||
|
|
||||||
|
switch (frequency) {
|
||||||
|
case DAYS:
|
||||||
|
nextDepositDate = lastDepositDate.plusDays(recurringEvery);
|
||||||
|
break;
|
||||||
|
case WEEKS:
|
||||||
|
nextDepositDate = lastDepositDate.plusWeeks(recurringEvery);
|
||||||
|
break;
|
||||||
|
case MONTHS:
|
||||||
|
nextDepositDate = lastDepositDate.plusMonths(recurringEvery);
|
||||||
|
break;
|
||||||
|
case YEARS:
|
||||||
|
nextDepositDate = lastDepositDate.plusYears(recurringEvery);
|
||||||
|
break;
|
||||||
|
case INVALID:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nextDepositDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalDate calculateNextDepositDate(final LocalDate lastDepositDate, final String recurrence) {
|
||||||
|
final PeriodFrequencyType frequencyType = CalendarFrequencyType.from(CalendarUtils.getFrequency(recurrence));
|
||||||
|
Integer frequency = CalendarUtils.getInterval(recurrence);
|
||||||
|
frequency = frequency == -1 ? 1 : frequency;
|
||||||
|
return calculateNextDepositDate(lastDepositDate, frequencyType, frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+13
-6
@@ -125,7 +125,7 @@ public class DepositAccountDataValidator {
|
|||||||
|
|
||||||
validateDepositDetailsForUpdate(element, baseDataValidator);
|
validateDepositDetailsForUpdate(element, baseDataValidator);
|
||||||
validatePreClosureDetailForUpdate(element, baseDataValidator);
|
validatePreClosureDetailForUpdate(element, baseDataValidator);
|
||||||
validateDepositTermDeatilForUpdate(element, baseDataValidator);
|
validateDepositTermDeatilForUpdate(element, baseDataValidator, DepositAccountType.FIXED_DEPOSIT);
|
||||||
// validateSavingsCharges(element, baseDataValidator);
|
// validateSavingsCharges(element, baseDataValidator);
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
@@ -166,7 +166,7 @@ public class DepositAccountDataValidator {
|
|||||||
|
|
||||||
validateDepositDetailsForUpdate(element, baseDataValidator);
|
validateDepositDetailsForUpdate(element, baseDataValidator);
|
||||||
validatePreClosureDetailForUpdate(element, baseDataValidator);
|
validatePreClosureDetailForUpdate(element, baseDataValidator);
|
||||||
validateDepositTermDeatilForUpdate(element, baseDataValidator);
|
validateDepositTermDeatilForUpdate(element, baseDataValidator, DepositAccountType.RECURRING_DEPOSIT);
|
||||||
validateRecurringDetailForUpdate(element, baseDataValidator);
|
validateRecurringDetailForUpdate(element, baseDataValidator);
|
||||||
// validateSavingsCharges(element, baseDataValidator);
|
// validateSavingsCharges(element, baseDataValidator);
|
||||||
|
|
||||||
@@ -494,8 +494,10 @@ public class DepositAccountDataValidator {
|
|||||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notNull().positiveAmount();
|
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notNull().positiveAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Integer depositPeriod = fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodParamName, element);
|
if (depositType.isFixedDeposit() || fromApiJsonHelper.parameterExists(depositPeriodParamName, element)) {
|
||||||
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod).notNull().integerGreaterThanZero();
|
final Integer depositPeriod = fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
final Integer depositPeriodFrequencyId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodFrequencyIdParamName,
|
final Integer depositPeriodFrequencyId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodFrequencyIdParamName,
|
||||||
element);
|
element);
|
||||||
@@ -503,7 +505,8 @@ public class DepositAccountDataValidator {
|
|||||||
.isOneOfTheseValues(SavingsPeriodFrequencyType.integerValues());
|
.isOneOfTheseValues(SavingsPeriodFrequencyType.integerValues());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateDepositTermDeatilForUpdate(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
|
private void validateDepositTermDeatilForUpdate(final JsonElement element, final DataValidatorBuilder baseDataValidator,
|
||||||
|
final DepositAccountType depositAccountType) {
|
||||||
this.productDataValidator.validateDepositTermDetailForUpdate(element, baseDataValidator);
|
this.productDataValidator.validateDepositTermDetailForUpdate(element, baseDataValidator);
|
||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists(depositAmountParamName, element)) {
|
if (fromApiJsonHelper.parameterExists(depositAmountParamName, element)) {
|
||||||
@@ -513,7 +516,11 @@ public class DepositAccountDataValidator {
|
|||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists(depositPeriodParamName, element)) {
|
if (fromApiJsonHelper.parameterExists(depositPeriodParamName, element)) {
|
||||||
final Integer depositPeriod = fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodParamName, element);
|
final Integer depositPeriod = fromApiJsonHelper.extractIntegerSansLocaleNamed(depositPeriodParamName, element);
|
||||||
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod).notNull().integerGreaterThanZero();
|
if (depositAccountType.isFixedDeposit()) {
|
||||||
|
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod).notNull().integerGreaterThanZero();
|
||||||
|
} else {
|
||||||
|
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists(depositPeriodFrequencyIdParamName, element)) {
|
if (fromApiJsonHelper.parameterExists(depositPeriodFrequencyIdParamName, element)) {
|
||||||
|
|||||||
+1
-1
@@ -221,7 +221,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
|
|||||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
|
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
|
||||||
Long savingsTransactionId = null;
|
Long savingsTransactionId = null;
|
||||||
account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, closedDate);
|
||||||
final BigDecimal transactionAmount = account.getAccountBalance();
|
final BigDecimal transactionAmount = account.getAccountBalance();
|
||||||
final Integer onAccountClosureId = command.integerValueOfParameterNamed(onAccountClosureIdParamName);
|
final Integer onAccountClosureId = command.integerValueOfParameterNamed(onAccountClosureIdParamName);
|
||||||
final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId);
|
final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId);
|
||||||
|
|||||||
+5
@@ -195,6 +195,11 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
|
|||||||
this.maturityAmount = this.depositAmount.add(interestPayable);
|
this.maturityAmount = this.depositAmount.add(interestPayable);
|
||||||
this.maturityDate = maturityDate.toDate();
|
this.maturityDate = maturityDate.toDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateDepositAmount(final BigDecimal depositAmount) {
|
||||||
|
this.depositAmount = depositAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public LocalDate getMaturityLocalDate() {
|
public LocalDate getMaturityLocalDate() {
|
||||||
LocalDate maturityLocalDate = null;
|
LocalDate maturityLocalDate = null;
|
||||||
|
|||||||
+86
-70
@@ -49,6 +49,7 @@ import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
|||||||
import org.mifosplatform.portfolio.group.domain.Group;
|
import org.mifosplatform.portfolio.group.domain.Group;
|
||||||
import org.mifosplatform.portfolio.interestratechart.domain.InterestRateChart;
|
import org.mifosplatform.portfolio.interestratechart.domain.InterestRateChart;
|
||||||
import org.mifosplatform.portfolio.savings.DepositAccountOnClosureType;
|
import org.mifosplatform.portfolio.savings.DepositAccountOnClosureType;
|
||||||
|
import org.mifosplatform.portfolio.savings.DepositAccountUtils;
|
||||||
import org.mifosplatform.portfolio.savings.DepositsApiConstants;
|
import org.mifosplatform.portfolio.savings.DepositsApiConstants;
|
||||||
import org.mifosplatform.portfolio.savings.PreClosurePenalInterestOnType;
|
import org.mifosplatform.portfolio.savings.PreClosurePenalInterestOnType;
|
||||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||||
@@ -192,6 +193,10 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (depositCloseDate == null) {
|
||||||
|
depositCloseDate = LocalDate.now();
|
||||||
|
}
|
||||||
|
|
||||||
final BigDecimal depositAmount = accountTermAndPreClosure.depositAmount();
|
final BigDecimal depositAmount = accountTermAndPreClosure.depositAmount();
|
||||||
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(depositAmount, depositStartDate(), depositCloseDate,
|
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(depositAmount, depositStartDate(), depositCloseDate,
|
||||||
this.client);
|
this.client);
|
||||||
@@ -209,8 +214,16 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure,
|
public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure,
|
||||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
|
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
|
||||||
final LocalDate maturityDate = calculateMaturityDate();
|
final LocalDate maturityDate = calculateMaturityDate();
|
||||||
final LocalDate interestCalculationUpto = maturityDate.minusDays(1);
|
LocalDate interestCalculationUpto = null;
|
||||||
final List<SavingsAccountTransaction> allTransactions = generateIncludingFutureTransactions(interestCalculationUpto);
|
List<SavingsAccountTransaction> allTransactions = null;
|
||||||
|
if (maturityDate == null) {
|
||||||
|
interestCalculationUpto = DateUtils.getLocalDateOfTenant();
|
||||||
|
allTransactions = getTransactions(interestCalculationUpto, false);
|
||||||
|
} else {
|
||||||
|
interestCalculationUpto = maturityDate.minusDays(1);
|
||||||
|
allTransactions = getTransactions(interestCalculationUpto, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, allTransactions,
|
final List<PostingPeriod> postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, allTransactions,
|
||||||
isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||||
@@ -220,8 +233,12 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
totalInterestPayable = totalInterestPayable.plus(postingPeriod.getInterestEarned());
|
totalInterestPayable = totalInterestPayable.plus(postingPeriod.getInterestEarned());
|
||||||
totalDepositAmount = totalDepositAmount.plus(postingPeriod.closingBalance()).minus(postingPeriod.openingBalance());
|
totalDepositAmount = totalDepositAmount.plus(postingPeriod.closingBalance()).minus(postingPeriod.openingBalance());
|
||||||
}
|
}
|
||||||
|
if (maturityDate == null) {
|
||||||
this.accountTermAndPreClosure.updateMaturityDetails(totalDepositAmount.getAmount(), totalInterestPayable.getAmount(), maturityDate);
|
this.accountTermAndPreClosure.updateDepositAmount(totalDepositAmount.getAmount());
|
||||||
|
} else {
|
||||||
|
this.accountTermAndPreClosure.updateMaturityDetails(totalDepositAmount.getAmount(), totalInterestPayable.getAmount(),
|
||||||
|
maturityDate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMaturityStatus(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
|
public void updateMaturityStatus(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
|
||||||
@@ -239,7 +256,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
if (!this.maturityDate().isAfter(todayDate)) {
|
if (!this.maturityDate().isAfter(todayDate)) {
|
||||||
// update account status
|
// update account status
|
||||||
this.status = SavingsAccountStatusType.MATURED.getValue();
|
this.status = SavingsAccountStatusType.MATURED.getValue();
|
||||||
postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, todayDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +265,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
final LocalDate startDate = depositStartDate();
|
final LocalDate startDate = depositStartDate();
|
||||||
LocalDate maturityDate = null;
|
LocalDate maturityDate = null;
|
||||||
final Integer depositPeriod = this.accountTermAndPreClosure.depositPeriod();
|
final Integer depositPeriod = this.accountTermAndPreClosure.depositPeriod();
|
||||||
|
if (depositPeriod == null) { return maturityDate; }
|
||||||
switch (this.accountTermAndPreClosure.depositPeriodFrequencyType()) {
|
switch (this.accountTermAndPreClosure.depositPeriodFrequencyType()) {
|
||||||
case DAYS:
|
case DAYS:
|
||||||
maturityDate = startDate.plusDays(depositPeriod);
|
maturityDate = startDate.plusDays(depositPeriod);
|
||||||
@@ -315,16 +333,18 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
return allPostingPeriods;
|
return allPostingPeriods;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SavingsAccountTransaction> generateIncludingFutureTransactions(final LocalDate depositEndDate) {
|
private List<SavingsAccountTransaction> getTransactions(final LocalDate depositEndDate, final boolean generateFutureTransactions) {
|
||||||
List<SavingsAccountTransaction> allTransactions = new ArrayList<>();
|
List<SavingsAccountTransaction> allTransactions = new ArrayList<>();
|
||||||
// add existing transactions
|
// add existing transactions
|
||||||
allTransactions.addAll(retreiveOrderedNonInterestPostingTransactions());
|
allTransactions.addAll(retreiveOrderedNonInterestPostingTransactions());
|
||||||
for (RecurringDepositScheduleInstallment installment : depositScheduleInstallments()) {
|
if (generateFutureTransactions) {
|
||||||
if (installment.isPrincipalNotCompleted(getCurrency())) {
|
for (RecurringDepositScheduleInstallment installment : depositScheduleInstallments()) {
|
||||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction
|
if (installment.isPrincipalNotCompleted(getCurrency())) {
|
||||||
.deposit(null, office(), null, installment.dueDate(), installment.getDepositAmountOutstanding(getCurrency()),
|
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null,
|
||||||
installment.dueDate().toDate(), null);
|
installment.dueDate(), installment.getDepositAmountOutstanding(getCurrency()), installment.dueDate().toDate(),
|
||||||
allTransactions.add(transaction);
|
null);
|
||||||
|
allTransactions.add(transaction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,29 +378,6 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
return allTransactions;
|
return allTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalDate calculateNextDepositDate(final LocalDate lastDepositDate, final PeriodFrequencyType frequency,
|
|
||||||
final int recurringEvery) {
|
|
||||||
LocalDate nextDepositDate = lastDepositDate;
|
|
||||||
|
|
||||||
switch (frequency) {
|
|
||||||
case DAYS:
|
|
||||||
nextDepositDate = lastDepositDate.plusDays(recurringEvery);
|
|
||||||
break;
|
|
||||||
case WEEKS:
|
|
||||||
nextDepositDate = lastDepositDate.plusWeeks(recurringEvery);
|
|
||||||
break;
|
|
||||||
case MONTHS:
|
|
||||||
nextDepositDate = lastDepositDate.plusMonths(recurringEvery);
|
|
||||||
break;
|
|
||||||
case YEARS:
|
|
||||||
nextDepositDate = lastDepositDate.plusYears(recurringEvery);
|
|
||||||
break;
|
|
||||||
case INVALID:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nextDepositDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDate depositStartDate() {
|
public LocalDate depositStartDate() {
|
||||||
final LocalDate depositStartDate = accountTermAndPreClosure.getExpectedFirstDepositOnDate();
|
final LocalDate depositStartDate = accountTermAndPreClosure.getExpectedFirstDepositOnDate();
|
||||||
if (depositStartDate == null) return accountSubmittedOrActivationDate();
|
if (depositStartDate == null) return accountSubmittedOrActivationDate();
|
||||||
@@ -500,7 +497,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.closeAction);
|
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.closeAction);
|
||||||
|
|
||||||
final SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
|
final SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
|
||||||
if (!SavingsAccountStatusType.MATURED.hasStateOf(currentStatus)) {
|
if (!SavingsAccountStatusType.MATURED.hasStateOf(currentStatus) && this.maturityDate() != null) {
|
||||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.in.matured.state");
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.in.matured.state");
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
}
|
}
|
||||||
@@ -514,7 +511,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
.failWithCode("must.be.after.activation.date");
|
.failWithCode("must.be.after.activation.date");
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
}
|
}
|
||||||
if (closedDate.isBefore(maturityDate())) {
|
if (maturityDate() != null && closedDate.isBefore(maturityDate())) {
|
||||||
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
|
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
|
||||||
.failWithCode("must.be.after.account.maturity.date");
|
.failWithCode("must.be.after.account.maturity.date");
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
@@ -564,11 +561,15 @@ 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 postMaturityInterest(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
|
public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||||
final LocalDate interestPostingUpToDate = maturityDate();
|
final LocalDate closeDate) {
|
||||||
|
LocalDate interestPostingUpToDate = maturityDate();
|
||||||
|
if (interestPostingUpToDate == null) {
|
||||||
|
interestPostingUpToDate = closeDate;
|
||||||
|
}
|
||||||
final MathContext mc = MathContext.DECIMAL64;
|
final MathContext mc = MathContext.DECIMAL64;
|
||||||
boolean isInterestTransfer = false;
|
boolean isInterestTransfer = false;
|
||||||
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
|
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate.minusDays(1), isInterestTransfer,
|
||||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||||
|
|
||||||
Money interestPostedToDate = Money.zero(this.currency);
|
Money interestPostedToDate = Money.zero(this.currency);
|
||||||
@@ -895,7 +896,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
|
|
||||||
private boolean isBeforeMaturityDate(final LocalDate compareDate) {
|
private boolean isBeforeMaturityDate(final LocalDate compareDate) {
|
||||||
final LocalDate maturityDate = this.maturityDate();
|
final LocalDate maturityDate = this.maturityDate();
|
||||||
return compareDate.isBefore(maturityDate);
|
return maturityDate == null ? true : compareDate.isBefore(maturityDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBeforeDepositStartDate(LocalDate compareDate) {
|
private boolean isBeforeDepositStartDate(LocalDate compareDate) {
|
||||||
@@ -923,30 +924,35 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Integer depositPeriod = this.accountTermAndPreClosure.depositPeriod();
|
final Integer depositPeriod = this.accountTermAndPreClosure.depositPeriod();
|
||||||
final SavingsPeriodFrequencyType depositPeriodFrequencyType = this.accountTermAndPreClosure.depositPeriodFrequencyType();
|
if (this.accountTermAndPreClosure.depositTermDetail().maxDepositTerm() != null) {
|
||||||
final boolean isValidDepositPeriod = this.accountTermAndPreClosure.depositTermDetail().isDepositBetweenMinAndMax(
|
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod).notNull();
|
||||||
depositStartDate(), calculateMaturityDate());
|
}
|
||||||
if (!isValidDepositPeriod) {
|
if (depositPeriod != null) {
|
||||||
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod)
|
final SavingsPeriodFrequencyType depositPeriodFrequencyType = this.accountTermAndPreClosure.depositPeriodFrequencyType();
|
||||||
.failWithCodeNoParameterAddedToErrorCode("deposit.period.not.between.min.and.max.deposit.term");
|
final boolean isValidDepositPeriod = this.accountTermAndPreClosure.depositTermDetail().isDepositBetweenMinAndMax(
|
||||||
} else {
|
depositStartDate(), calculateMaturityDate());
|
||||||
final Integer inMultiplesOf = this.accountTermAndPreClosure.depositTermDetail().inMultiplesOfDepositTerm();
|
if (!isValidDepositPeriod) {
|
||||||
if (inMultiplesOf != null) {
|
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod)
|
||||||
final boolean isValid = this.accountTermAndPreClosure.depositTermDetail().isValidInMultiplesOfPeriod(depositPeriod,
|
.failWithCodeNoParameterAddedToErrorCode("deposit.period.not.between.min.and.max.deposit.term");
|
||||||
depositPeriodFrequencyType);
|
} else {
|
||||||
if (!isValid) {
|
final Integer inMultiplesOf = this.accountTermAndPreClosure.depositTermDetail().inMultiplesOfDepositTerm();
|
||||||
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod)
|
if (inMultiplesOf != null) {
|
||||||
.failWithCodeNoParameterAddedToErrorCode("deposit.period.not.multiple.of.term");
|
final boolean isValid = this.accountTermAndPreClosure.depositTermDetail().isValidInMultiplesOfPeriod(depositPeriod,
|
||||||
|
depositPeriodFrequencyType);
|
||||||
|
if (!isValid) {
|
||||||
|
baseDataValidator.reset().parameter(depositPeriodParamName).value(depositPeriod)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("deposit.period.not.multiple.of.term");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (isAccountLocked(calculateMaturityDate())) {
|
||||||
if (isAccountLocked(calculateMaturityDate())) {
|
baseDataValidator
|
||||||
baseDataValidator
|
.reset()
|
||||||
.reset()
|
.parameter(depositPeriodParamName)
|
||||||
.parameter(depositPeriodParamName)
|
.value(depositPeriod)
|
||||||
.value(depositPeriod)
|
.failWithCode("deposit.period.must.be.greater.than.lock.in.period",
|
||||||
.failWithCode("deposit.period.must.be.greater.than.lock.in.period",
|
"Deposit period must be greater than account lock-in period.");
|
||||||
"Deposit period must be greater than account lock-in period.");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstDepositDateBeforeAccountSubmittedOrActivationDate()) {
|
if (firstDepositDateBeforeAccountSubmittedOrActivationDate()) {
|
||||||
@@ -969,8 +975,8 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||||
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME);
|
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME);
|
||||||
|
LocalDate maturityDate = calculateMaturityDate();
|
||||||
if (this.chart != null) {
|
if (this.chart != null && maturityDate != null) {
|
||||||
final LocalDate chartFromDate = this.chart.getFromDateAsLocalDate();
|
final LocalDate chartFromDate = this.chart.getFromDateAsLocalDate();
|
||||||
LocalDate chartEndDate = this.chart.getEndDateAsLocalDate();
|
LocalDate chartEndDate = this.chart.getEndDateAsLocalDate();
|
||||||
chartEndDate = chartEndDate == null ? DateUtils.getLocalDateOfTenant() : chartEndDate;
|
chartEndDate = chartEndDate == null ? DateUtils.getLocalDateOfTenant() : chartEndDate;
|
||||||
@@ -981,8 +987,8 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final BigDecimal maturityAmount = this.accountTermAndPreClosure.maturityAmount();
|
final BigDecimal maturityAmount = this.accountTermAndPreClosure.maturityAmount();
|
||||||
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(maturityAmount, depositStartDate(),
|
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(maturityAmount, depositStartDate(), maturityDate,
|
||||||
calculateMaturityDate(), this.client);
|
this.client);
|
||||||
|
|
||||||
if (applicableInterestRate.equals(BigDecimal.ZERO)) {
|
if (applicableInterestRate.equals(BigDecimal.ZERO)) {
|
||||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
||||||
@@ -1088,18 +1094,28 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
installmentDate = depositStartDate();
|
installmentDate = depositStartDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocalDate maturityDate = calculateMaturityDate();
|
|
||||||
int installmentNumber = 1;
|
int installmentNumber = 1;
|
||||||
|
final LocalDate maturityDate = calcualteScheduleTillDate(frequency, recurringEvery);
|
||||||
final BigDecimal depositAmount = this.recurringDetail.mandatoryRecommendedDepositAmount();
|
final BigDecimal depositAmount = this.recurringDetail.mandatoryRecommendedDepositAmount();
|
||||||
while (maturityDate.isAfter(installmentDate)) {
|
while (maturityDate.isAfter(installmentDate)) {
|
||||||
final RecurringDepositScheduleInstallment installment = RecurringDepositScheduleInstallment.installment(this,
|
final RecurringDepositScheduleInstallment installment = RecurringDepositScheduleInstallment.installment(this,
|
||||||
installmentNumber, installmentDate.toDate(), depositAmount);
|
installmentNumber, installmentDate.toDate(), depositAmount);
|
||||||
depositScheduleInstallments.add(installment);
|
depositScheduleInstallments.add(installment);
|
||||||
installmentDate = calculateNextDepositDate(installmentDate, frequency, recurringEvery);
|
installmentDate = DepositAccountUtils.calculateNextDepositDate(installmentDate, frequency, recurringEvery);
|
||||||
installmentNumber += 1;
|
installmentNumber += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LocalDate calcualteScheduleTillDate(final PeriodFrequencyType frequency, final Integer recurringEvery) {
|
||||||
|
LocalDate tillDate = calculateMaturityDate();
|
||||||
|
if (tillDate == null) {
|
||||||
|
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||||
|
tillDate = DepositAccountUtils.calculateNextDepositDate(today, frequency, recurringEvery
|
||||||
|
* (DepositAccountUtils.GENERATE_MINIMUM_NUMBER_OF_FUTURE_INSTALMENTS + 1));
|
||||||
|
}
|
||||||
|
return tillDate;
|
||||||
|
}
|
||||||
|
|
||||||
private List<RecurringDepositScheduleInstallment> depositScheduleInstallments() {
|
private List<RecurringDepositScheduleInstallment> depositScheduleInstallments() {
|
||||||
if (this.depositScheduleInstallments == null) {
|
if (this.depositScheduleInstallments == null) {
|
||||||
this.depositScheduleInstallments = new ArrayList<>();
|
this.depositScheduleInstallments = new ArrayList<>();
|
||||||
@@ -1113,7 +1129,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
|||||||
|
|
||||||
public void updateOverduePayments(final LocalDate todayDate) {
|
public void updateOverduePayments(final LocalDate todayDate) {
|
||||||
LocalDate overdueUptoDate = this.maturityDate();
|
LocalDate overdueUptoDate = this.maturityDate();
|
||||||
if (overdueUptoDate.isAfter(todayDate)) {
|
if (overdueUptoDate == null || overdueUptoDate.isAfter(todayDate)) {
|
||||||
overdueUptoDate = todayDate;
|
overdueUptoDate = todayDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -6,6 +6,7 @@
|
|||||||
package org.mifosplatform.portfolio.savings.service;
|
package org.mifosplatform.portfolio.savings.service;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.data.PaginationParameters;
|
import org.mifosplatform.infrastructure.core.data.PaginationParameters;
|
||||||
import org.mifosplatform.infrastructure.core.service.Page;
|
import org.mifosplatform.infrastructure.core.service.Page;
|
||||||
@@ -38,4 +39,6 @@ public interface DepositAccountReadPlatformService {
|
|||||||
SavingsAccountTransactionData retrieveRecurringAccountDepositTransactionTemplate(final Long accountId);
|
SavingsAccountTransactionData retrieveRecurringAccountDepositTransactionTemplate(final Long accountId);
|
||||||
|
|
||||||
Collection<AccountTransferDTO> retrieveDataForInterestTransfer();
|
Collection<AccountTransferDTO> retrieveDataForInterestTransfer();
|
||||||
|
|
||||||
|
Collection<Map<String, Object>> retriveDataForRDScheduleCreation();
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-3
@@ -10,14 +10,18 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||||
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
|
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
import org.mifosplatform.infrastructure.core.data.PaginationParameters;
|
import org.mifosplatform.infrastructure.core.data.PaginationParameters;
|
||||||
import org.mifosplatform.infrastructure.core.data.PaginationParametersDataValidator;
|
import org.mifosplatform.infrastructure.core.data.PaginationParametersDataValidator;
|
||||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
import org.mifosplatform.infrastructure.core.service.Page;
|
import org.mifosplatform.infrastructure.core.service.Page;
|
||||||
import org.mifosplatform.infrastructure.core.service.PaginationHelper;
|
import org.mifosplatform.infrastructure.core.service.PaginationHelper;
|
||||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||||
@@ -32,6 +36,7 @@ import org.mifosplatform.portfolio.account.domain.AccountTransferType;
|
|||||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
||||||
|
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||||
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
|
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||||
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
|
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
|
||||||
@@ -103,6 +108,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
private final RecurringAccountDepositTransactionTemplateMapper rdTransactionTemplateMapper;
|
private final RecurringAccountDepositTransactionTemplateMapper rdTransactionTemplateMapper;
|
||||||
private final DropdownReadPlatformService dropdownReadPlatformService;
|
private final DropdownReadPlatformService dropdownReadPlatformService;
|
||||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||||
|
private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public DepositAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
|
public DepositAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
|
||||||
@@ -197,9 +203,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
sqlBuilder.append(this.depositAccountForMaturityRowMapper.schema());
|
sqlBuilder.append(this.depositAccountForMaturityRowMapper.schema());
|
||||||
sqlBuilder.append(" WHERE da.deposit_type_enum in (?, ?) and da.status_enum = ?");
|
sqlBuilder.append(" WHERE da.deposit_type_enum in (?, ?) and da.status_enum = ?");
|
||||||
|
|
||||||
return this.jdbcTemplate.query(sqlBuilder.toString(), this.depositAccountForMaturityRowMapper, new Object[] {
|
LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||||
DepositAccountType.FIXED_DEPOSIT.getValue(), DepositAccountType.RECURRING_DEPOSIT.getValue(),
|
|
||||||
SavingsAccountStatusType.ACTIVE.getValue() });
|
return this.jdbcTemplate.query(
|
||||||
|
sqlBuilder.toString(),
|
||||||
|
this.depositAccountForMaturityRowMapper,
|
||||||
|
new Object[] { formatter.print(today), DepositAccountType.FIXED_DEPOSIT.getValue(),
|
||||||
|
DepositAccountType.RECURRING_DEPOSIT.getValue(), SavingsAccountStatusType.ACTIVE.getValue() });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -482,6 +492,27 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
SavingsAccountTransactionType.INTEREST_POSTING.getValue(), SavingsAccountStatusType.ACTIVE.getValue() });
|
SavingsAccountTransactionType.INTEREST_POSTING.getValue(), SavingsAccountStatusType.ACTIVE.getValue() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Map<String, Object>> retriveDataForRDScheduleCreation() {
|
||||||
|
final StringBuilder sb = new StringBuilder(300);
|
||||||
|
sb.append(" select rd.savings_account_id savingsId, rd.mandatory_recommended_deposit_amount as amount,");
|
||||||
|
sb.append(" mc.recurrence as recurrence ,");
|
||||||
|
sb.append(" max(ms.duedate) as dueDate , max(ms.installment) as installment,");
|
||||||
|
sb.append(" count(ms.installment) as futureInstallemts");
|
||||||
|
sb.append(" from m_deposit_account_term_and_preclosure dat ");
|
||||||
|
sb.append(" inner join m_savings_account sa on sa.id = dat.savings_account_id and sa.status_enum = ?");
|
||||||
|
sb.append(" inner join m_deposit_account_recurring_detail rd on rd.savings_account_id = dat.savings_account_id ");
|
||||||
|
sb.append(" inner join m_calendar_instance mci on mci.entity_type_enum = ? and mci.entity_id = dat.savings_account_id ");
|
||||||
|
sb.append(" inner join m_calendar mc on mc.id = mci.calendar_id and mc.calendar_type_enum = ?");
|
||||||
|
sb.append(" inner join m_mandatory_savings_schedule ms on ms.savings_account_id = dat.savings_account_id and ms.duedate > ?");
|
||||||
|
sb.append(" where dat.deposit_period is null");
|
||||||
|
sb.append(" group by ms.savings_account_id");
|
||||||
|
|
||||||
|
return this.jdbcTemplate.queryForList(sb.toString(), SavingsAccountStatusType.ACTIVE.getValue(),
|
||||||
|
CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue(),
|
||||||
|
formatter.print(DateUtils.getLocalDateOfTenant()));
|
||||||
|
}
|
||||||
|
|
||||||
private static abstract class DepositAccountMapper implements RowMapper<DepositAccountData> {
|
private static abstract class DepositAccountMapper implements RowMapper<DepositAccountData> {
|
||||||
|
|
||||||
private final String selectFieldsSql;
|
private final String selectFieldsSql;
|
||||||
@@ -1300,6 +1331,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
sqlBuilder.append("da.account_no as accountNumber, ");
|
sqlBuilder.append("da.account_no as accountNumber, ");
|
||||||
sqlBuilder.append("da.deposit_type_enum as depositTypeId ");
|
sqlBuilder.append("da.deposit_type_enum as depositTypeId ");
|
||||||
sqlBuilder.append("FROM m_savings_account da ");
|
sqlBuilder.append("FROM m_savings_account da ");
|
||||||
|
sqlBuilder.append("inner join m_deposit_account_term_and_preclosure dat on dat.savings_account_id = da.id ");
|
||||||
|
sqlBuilder.append("and dat.maturity_date is not null and dat.maturity_date <= ? ");
|
||||||
|
|
||||||
this.schemaSql = sqlBuilder.toString();
|
this.schemaSql = sqlBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-6
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.savings.service;
|
package org.mifosplatform.portfolio.savings.service;
|
||||||
|
|
||||||
|
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME;
|
||||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||||
@@ -312,8 +313,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
|||||||
financialYearBeginningMonth);
|
financialYearBeginningMonth);
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils
|
final LocalDate overdueUptoDate = DateUtils.getLocalDateOfTenant();
|
||||||
.getLocalDateOfTenant() : account.maturityDate();
|
|
||||||
account.updateOverduePayments(overdueUptoDate);
|
account.updateOverduePayments(overdueUptoDate);
|
||||||
final boolean isInterestTransfer = false;
|
final boolean isInterestTransfer = false;
|
||||||
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) {
|
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) {
|
||||||
@@ -586,8 +586,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
|||||||
final boolean isPreMatureClosure = false;
|
final boolean isPreMatureClosure = false;
|
||||||
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||||
|
|
||||||
final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils
|
final LocalDate overdueUptoDate = DateUtils.getLocalDateOfTenant();
|
||||||
.getLocalDateOfTenant() : account.maturityDate();
|
|
||||||
|
|
||||||
if (savingsAccountTransaction.isDeposit()) {
|
if (savingsAccountTransaction.isDeposit()) {
|
||||||
account.updateScheduleInstallments();
|
account.updateScheduleInstallments();
|
||||||
@@ -682,8 +681,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
|||||||
if (savingsAccountTransaction.isDeposit()) {
|
if (savingsAccountTransaction.isDeposit()) {
|
||||||
account.handleScheduleInstallments(savingsAccountTransaction);
|
account.handleScheduleInstallments(savingsAccountTransaction);
|
||||||
}
|
}
|
||||||
final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils
|
final LocalDate overdueUptoDate = DateUtils.getLocalDateOfTenant();
|
||||||
.getLocalDateOfTenant() : account.maturityDate();
|
|
||||||
account.updateOverduePayments(overdueUptoDate);
|
account.updateOverduePayments(overdueUptoDate);
|
||||||
|
|
||||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||||
@@ -833,6 +831,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
|||||||
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(savingsId,
|
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(savingsId,
|
||||||
DepositAccountType.RECURRING_DEPOSIT);
|
DepositAccountType.RECURRING_DEPOSIT);
|
||||||
checkClientOrGroupActive(account);
|
checkClientOrGroupActive(account);
|
||||||
|
if (account.maturityDate() == null) {
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||||
|
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME + DepositsApiConstants.preMatureCloseAction);
|
||||||
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("can.not.close.as.premature");
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
}
|
||||||
|
|
||||||
this.depositAccountDomainService.handleRDAccountPreMatureClosure(account, paymentDetail, user, command,
|
this.depositAccountDomainService.handleRDAccountPreMatureClosure(account, paymentDetail, user, command,
|
||||||
DateUtils.getLocalDateOfTenant(), changes);
|
DateUtils.getLocalDateOfTenant(), changes);
|
||||||
|
|||||||
+2
@@ -20,4 +20,6 @@ public interface ScheduledJobRunnerService {
|
|||||||
void updateNPA();
|
void updateNPA();
|
||||||
|
|
||||||
void updateMaturityDetailsOfDepositAccounts();
|
void updateMaturityDetailsOfDepositAccounts();
|
||||||
|
|
||||||
|
void generateRDSchedule();
|
||||||
}
|
}
|
||||||
|
|||||||
+66
@@ -5,17 +5,25 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.scheduledjobs.service;
|
package org.mifosplatform.scheduledjobs.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSourceServiceFactory;
|
import org.mifosplatform.infrastructure.core.service.RoutingDataSourceServiceFactory;
|
||||||
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||||
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
|
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
|
||||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||||
import org.mifosplatform.portfolio.savings.DepositAccountType;
|
import org.mifosplatform.portfolio.savings.DepositAccountType;
|
||||||
|
import org.mifosplatform.portfolio.savings.DepositAccountUtils;
|
||||||
import org.mifosplatform.portfolio.savings.data.DepositAccountData;
|
import org.mifosplatform.portfolio.savings.data.DepositAccountData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||||
import org.mifosplatform.portfolio.savings.service.DepositAccountReadPlatformService;
|
import org.mifosplatform.portfolio.savings.service.DepositAccountReadPlatformService;
|
||||||
@@ -33,6 +41,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService {
|
public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(ScheduledJobRunnerServiceImpl.class);
|
private final static Logger logger = LoggerFactory.getLogger(ScheduledJobRunnerServiceImpl.class);
|
||||||
|
private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
|
||||||
|
private final DateTimeFormatter formatterWithTime = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
private final RoutingDataSourceServiceFactory dataSourceServiceFactory;
|
private final RoutingDataSourceServiceFactory dataSourceServiceFactory;
|
||||||
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
|
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
|
||||||
@@ -285,4 +295,60 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
|||||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Deposit accounts affected by update: " + depositAccounts.size());
|
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Deposit accounts affected by update: " + depositAccounts.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CronTarget(jobName = JobName.GENERATE_RD_SCEHDULE)
|
||||||
|
public void generateRDSchedule() {
|
||||||
|
final JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSourceServiceFactory.determineDataSourceService().retrieveDataSource());
|
||||||
|
final Collection<Map<String, Object>> scheduleDetails = this.depositAccountReadPlatformService.retriveDataForRDScheduleCreation();
|
||||||
|
String insertSql = "INSERT INTO `m_mandatory_savings_schedule` (`savings_account_id`, `duedate`, `installment`, `deposit_amount`, `completed_derived`, `created_date`, `lastmodified_date`) VALUES ";
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String currentDate = formatterWithTime.print(DateUtils.getLocalDateTimeOfTenant());
|
||||||
|
int iterations = 0;
|
||||||
|
for (Map<String, Object> details : scheduleDetails) {
|
||||||
|
Long count = (Long) details.get("futureInstallemts");
|
||||||
|
if (count == null) {
|
||||||
|
count = 0l;
|
||||||
|
}
|
||||||
|
final Long savingsId = (Long) details.get("savingsId");
|
||||||
|
final BigDecimal amount = (BigDecimal) details.get("amount");
|
||||||
|
final String recurrence = (String) details.get("recurrence");
|
||||||
|
Date date = (Date) details.get("dueDate");
|
||||||
|
LocalDate lastDepositDate = new LocalDate(date);
|
||||||
|
Integer installmentNumber = (Integer) details.get("installment");
|
||||||
|
while (count < DepositAccountUtils.GENERATE_MINIMUM_NUMBER_OF_FUTURE_INSTALMENTS) {
|
||||||
|
count++;
|
||||||
|
installmentNumber++;
|
||||||
|
lastDepositDate = DepositAccountUtils.calculateNextDepositDate(lastDepositDate, recurrence);
|
||||||
|
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append("(");
|
||||||
|
sb.append(savingsId);
|
||||||
|
sb.append(",'");
|
||||||
|
sb.append(formatter.print(lastDepositDate));
|
||||||
|
sb.append("',");
|
||||||
|
sb.append(installmentNumber);
|
||||||
|
sb.append(",");
|
||||||
|
sb.append(amount);
|
||||||
|
sb.append(", b'0','");
|
||||||
|
sb.append(currentDate);
|
||||||
|
sb.append("','");
|
||||||
|
sb.append(currentDate);
|
||||||
|
sb.append("')");
|
||||||
|
iterations++;
|
||||||
|
if (iterations > 200) {
|
||||||
|
jdbcTemplate.update(insertSql + sb.toString());
|
||||||
|
sb = new StringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
jdbcTemplate.update(insertSql + sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`) VALUES ('Generate Mandatory Savings Schedule', 'Generate Mandatory Savings Schedule', '0 5 0 1/1 * ? *', now());
|
||||||
|
|
||||||
Reference in New Issue
Block a user