Merge pull request #1049 from pramodn02/develop

MIFOSX-1418 : added regeneration of accrual entries
This commit is contained in:
Vishwas Babu A J
2014-08-16 02:38:41 -07:00
10 changed files with 207 additions and 23 deletions
@@ -810,7 +810,7 @@ public class AccountingScenarioIntegrationTest {
.withRepaymentAfterEvery(this.LP_REPAYMENT_PERIOD).withNumberOfRepayments(this.LP_REPAYMENTS).withRepaymentTypeAsMonth()
.withinterestRatePerPeriod(this.LP_INTEREST_RATE).withInterestRateFrequencyTypeAsMonths()
.withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRulePeriodicAccrual(accounts)
.build(null);
.withDaysInMonth("30").withDaysInYear("365").build(null);
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
}
@@ -31,7 +31,7 @@ public class LoanProductTestBuilder {
public static final String MIFOS_STANDARD_STRATEGY = "1";
// private static final String HEAVENS_FAMILY_STRATEGY ="2";
// private static final String CREO_CORE_STRATEGY ="3";
public static final String RBI_INDIA_STRATEGY ="4";
public static final String RBI_INDIA_STRATEGY = "4";
private static final String NONE = "1";
private static final String CASH_BASED = "2";
private static final String ACCRUAL_PERIODIC = "3";
@@ -63,7 +63,7 @@ public class LoanProductTestBuilder {
private Boolean multiDisburseLoan = false;
private String outstandingLoanBalance = "35000";
private String maxTrancheCount = "35000";
private Boolean isInterestRecalculationEnabled = false;
private String daysInYearType = "1";
private String daysInMonthType = "1";
@@ -328,4 +328,13 @@ public class LoanProductTestBuilder {
return this;
}
public LoanProductTestBuilder withDaysInMonth(final String daysInMonthType) {
this.daysInMonthType = daysInMonthType;
return this;
}
public LoanProductTestBuilder withDaysInYear(final String daysInYearType) {
this.daysInYearType = daysInYearType;
return this;
}
}
@@ -984,9 +984,36 @@ public class Loan extends AbstractPersistable<Long> {
updateLoanScheduleDependentDerivedFields();
updateLoanSummaryDerivedFields();
resetAccruals();
}
/**
* method to reverse all the accrual entries
*/
private void resetAccruals() {
if (!this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { return; }
List<LoanTransaction> transactions = this.getLoanTransactions();
for (final LoanTransaction transaction : transactions) {
if (transaction.isAccrual()) {
transaction.reverse();
}
}
}
public boolean isAccrualsPresent() {
boolean isAccrualsPresent = false;
if (!this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { return isAccrualsPresent; }
List<LoanTransaction> transactions = this.getLoanTransactions();
for (final LoanTransaction transaction : transactions) {
if (transaction.isAccrual() && transaction.isNotReversed()) {
isAccrualsPresent = true;
break;
}
}
return isAccrualsPresent;
}
private void updateLoanScheduleDependentDerivedFields() {
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
this.actualMaturityDate = determineExpectedMaturityDate().toDate();
@@ -3218,7 +3245,7 @@ public class Loan extends AbstractPersistable<Long> {
return matchesCurrentLoanOfficer;
}
private LocalDate getInterestChargedFromDate() {
public LocalDate getInterestChargedFromDate() {
LocalDate interestChargedFrom = null;
if (this.interestChargedFromDate != null) {
interestChargedFrom = new LocalDate(this.interestChargedFromDate);
@@ -3415,7 +3442,7 @@ public class Loan extends AbstractPersistable<Long> {
return this.loanProduct.isPeriodicAccrualAccountingEnabled();
}
private Long productId() {
public Long productId() {
return this.loanProduct.getId();
}
@@ -4170,4 +4197,12 @@ public class Loan extends AbstractPersistable<Long> {
public List<LoanRepaymentScheduleInstallment> fetchRepaymentScheduleInstallments() {
return this.repaymentScheduleInstallments;
}
public LocalDate getAccruedTill() {
LocalDate accruedTill = null;
if (this.accruedTill != null) {
accruedTill = new LocalDate(this.accruedTill);
}
return accruedTill;
}
}
@@ -30,4 +30,13 @@ public interface LoanAccountDomainService {
PaymentDetail paymentDetail, String noteText, String txnExternalId);
LocalDate getCalculatedRepaymentsStartingFromDate(LocalDate actualDisbursementDate, Loan loan, CalendarInstance calendarInstance);
/**
* This method is to recalculate and accrue the income till the last accrued
* date. this method is used when the schedule changes due to interest
* recalculation
*
* @param loan
*/
void recalculateAccruals(Loan loan);
}
@@ -8,8 +8,10 @@ package org.mifosplatform.portfolio.loanaccount.domain;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
@@ -22,6 +24,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
import org.mifosplatform.organisation.holiday.domain.Holiday;
import org.mifosplatform.organisation.holiday.domain.HolidayRepository;
import org.mifosplatform.organisation.holiday.domain.HolidayStatusType;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
@@ -37,9 +40,14 @@ import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
import org.mifosplatform.portfolio.common.domain.DaysInMonthType;
import org.mifosplatform.portfolio.common.domain.DaysInYearType;
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
import org.mifosplatform.portfolio.loanaccount.data.LoanScheduleAccrualData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.mifosplatform.portfolio.loanaccount.service.LoanAccrualWritePlatformService;
import org.mifosplatform.portfolio.loanaccount.service.LoanAssembler;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.note.domain.Note;
@@ -68,6 +76,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
private final CalendarInstanceRepository calendarInstanceRepository;
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
private final LoanAccrualWritePlatformService accrualWritePlatformService;
@Autowired
public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository,
@@ -79,7 +88,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final AccountTransferRepository accountTransferRepository, final LoanScheduleGeneratorFactory loanScheduleFactory,
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
final CalendarInstanceRepository calendarInstanceRepository,
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository) {
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
final LoanAccrualWritePlatformService accrualWritePlatformService) {
this.loanAccountAssembler = loanAccountAssembler;
this.loanRepository = loanRepository;
this.loanTransactionRepository = loanTransactionRepository;
@@ -94,6 +104,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
this.applicationCurrencyRepository = applicationCurrencyRepository;
this.calendarInstanceRepository = calendarInstanceRepository;
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
this.accrualWritePlatformService = accrualWritePlatformService;
}
@Transactional
@@ -187,6 +198,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
recalculateAccruals(loan);
builderResult.withEntityId(newRepaymentTransaction.getId()) //
.withOfficeId(loan.getOfficeId()) //
.withClientId(loan.getClientId()) //
@@ -210,7 +222,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
"Validation errors exist.", dataValidationErrors); }
}
}
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
try {
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
@@ -270,6 +282,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
recalculateAccruals(loan);
return newPaymentTransaction;
}
@@ -364,7 +377,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
return disbursementTransaction;
}
@@ -402,6 +414,67 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
return calculatedRepaymentsStartingFromDate;
}
/* (non-Javadoc)
* @see org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService#recalculateAccruals(org.mifosplatform.portfolio.loanaccount.domain.Loan)
*/
@Override
public void recalculateAccruals(Loan loan) {
LocalDate accruedTill = loan.getAccruedTill();
if (!loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || accruedTill == null || loan.isAccrualsPresent()) { return; }
Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = new ArrayList<>();
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
Long loanId = loan.getId();
DaysInMonthType daysInMonth = loan.repaymentScheduleDetail().fetchDaysInMonthType();
DaysInYearType daysInYear = loan.repaymentScheduleDetail().fetchDaysInYearType();
Long officeId = loan.getOfficeId();
LocalDate accrualStartDate = null;
PeriodFrequencyType repaymentFrequency = loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType();
Integer repayEvery = loan.repaymentScheduleDetail().getRepayEvery();
LocalDate interestCalculatedFrom = loan.getInterestChargedFromDate();
Long loanProductId = loan.productId();
MonetaryCurrency currency = loan.getCurrency();
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
CurrencyData currencyData = applicationCurrency.toData();
Set<LoanCharge> loanCharges = loan.charges();
BigDecimal accruedInterestIncome = null;
BigDecimal accruedFeeIncome = null;
BigDecimal accruedPenaltyIncome = null;
for (LoanRepaymentScheduleInstallment installment : installments) {
if (!accruedTill.isBefore(installment.getDueDate())
|| (accruedTill.isAfter(installment.getFromDate()) && !accruedTill.isAfter(installment.getDueDate()))) {
BigDecimal dueDateFeeIncome = BigDecimal.ZERO;
BigDecimal dueDatePenaltyIncome = BigDecimal.ZERO;
LocalDate chargesTillDate = installment.getDueDate();
if (!accruedTill.isAfter(installment.getDueDate())) {
chargesTillDate = accruedTill;
}
for (final LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(installment.getFromDate(), chargesTillDate)) {
if (loanCharge.isFeeCharge()) {
dueDateFeeIncome = dueDateFeeIncome.add(loanCharge.amount());
} else if (loanCharge.isPenaltyCharge()) {
dueDatePenaltyIncome = dueDatePenaltyIncome.add(loanCharge.amount());
}
}
}
LoanScheduleAccrualData accrualData = new LoanScheduleAccrualData(loanId, officeId, accrualStartDate,
daysInMonth.getValue(), daysInYear.getValue(), repaymentFrequency, repayEvery, installment.getDueDate(),
installment.getFromDate(), installment.getId(), loanProductId,
installment.getInterestCharged(currency).getAmount(), installment.getFeeChargesCharged(currency).getAmount(),
installment.getPenaltyChargesCharged(currency).getAmount(), accruedInterestIncome, accruedFeeIncome,
accruedPenaltyIncome, currencyData, dueDateFeeIncome, dueDatePenaltyIncome, interestCalculatedFrom);
loanScheduleAccrualDatas.add(accrualData);
}
}
if (!loanScheduleAccrualDatas.isEmpty()) {
this.accrualWritePlatformService.addPeriodicAccruals(accruedTill, loanScheduleAccrualDatas);
}
}
private void updateLoanTransaction(final Long loanTransactionId, final LoanTransaction newLoanTransaction) {
final AccountTransferTransaction transferTransaction = this.accountTransferRepository.findByToLoanTransactionId(loanTransactionId);
if (transferTransaction != null) {
@@ -146,6 +146,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms.getLoanTermPeriodFrequencyType(),
loanApplicationTerms.getRepaymentEvery());
Money balanceForcalculation = outstandingBalance;
// reduce principal is the early payment, will processed as per the
// reschedule strategy
if (reducePrincipal.isGreaterThanZero()) {
switch (loanApplicationTerms.getRescheduleStrategyMethod()) {
case REDUCE_EMI_AMOUNT:
@@ -211,10 +213,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
fixedEmiAmount = principalForThisPeriod.plus(interestForThisinstallment);
}
// this block is to identify interest based on late/early payment
if (diffAmt != null && !diffAmt.isEmpty()) {
BigDecimal interestDueToLatePayment = BigDecimal.ZERO;
BigDecimal interestReducedDueToEarlyPayment = BigDecimal.ZERO;
for (RecalculationDetail detail : diffAmt) {
// will increase the principal portion and reduces interest
// as per the number of days. and also identifies reduce
// principal for reschedule strategy
if (!detail.isLatePayment() && detail.getStartDate().isAfter(periodStartDate)
&& !detail.getStartDate().isAfter(scheduledDueDate)) {
reducePrincipal = reducePrincipal.plus(detail.getAmount());
@@ -234,7 +240,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
interestReducedDueToEarlyPayment = interestReducedDueToEarlyPayment.add(loanApplicationTerms.interestRateFor(
this.paymentPeriodsInOneYearCalculator, mc, detail.getAmount(), detail.getStartDate(), scheduledDueDate));
} else if (detail.isLatePayment() && detail.isOverlapping(periodStartDate, scheduledDueDate)
}
// calculates the interest for late payment and increase
// the interest for the installment
else if (detail.isLatePayment() && detail.isOverlapping(periodStartDate, scheduledDueDate)
&& periodStartDate.isBefore(LocalDate.now())) {
LocalDate fromDate = periodStartDate;
LocalDate toDate = scheduledDueDate;
@@ -312,6 +321,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
}
// this block is to add extra re-payment schedules with interest portion
// if the last payment is missed
if (diffAmt != null && !diffAmt.isEmpty() && !periodStartDate.isAfter(LocalDate.now())) {
Map<LocalDate, RecalculationDetail> processDetails = new TreeMap<>();
for (RecalculationDetail detail : diffAmt) {
@@ -518,6 +529,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
return cumulative;
}
/**
* Method calls schedule regeneration by passing transactions one after
* another(this is done mainly to handle the scenario where interest or fee
* of over due installment should be collected before collecting principal )
*/
@Override
public LoanScheduleModel rescheduleNextInstallments(final MathContext mc, final ApplicationCurrency applicationCurrency,
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
@@ -570,6 +586,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
return recalculateFrom;
}
/**
* Method calls regenerate schedule for a particular set of transactions
* till all the installments are processed to identify early or late
* payments and will be used in regeneration of schedule
*/
private LoanScheduleModel recalculateInstallment(final MathContext mc, final ApplicationCurrency applicationCurrency,
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
final List<Holiday> holidays, final WorkingDays workingDays,
@@ -593,6 +614,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
return loanScheduleModel;
}
/**
* Method identifies late or early payments for schedule recalculation.
*/
private RecalculatedSchedule recalculateInterest(final MathContext mc, final ApplicationCurrency applicationCurrency,
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
final List<Holiday> holidays, final WorkingDays workingDays, final List<LoanTransaction> transactions,
@@ -638,6 +662,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Map<LocalDate, Money> earlyPaymentMap = loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(
transactionsForInstallment, currency, processinstallmets, installment, recalculationDates);
// this block is to create early payment entries for schedule
// generation
for (Map.Entry<LocalDate, Money> entry : earlyPaymentMap.entrySet()) {
LocalDate startDate = entry.getKey();
if (unpaidPricipal.isGreaterThan(entry.getValue())) {
@@ -655,6 +681,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Money totalOutstanding = installment.getTotalOutstanding(currency);
boolean reduceStartDate = false;
// this block is to identify late payment based on the rest
// calculation date
while (totalOutstanding.isGreaterThanZero() && startDate.isBefore(LocalDate.now())) {
LocalDate recalculateFrom = getNextRestScheduleDate(startDate.minusDays(1), loanApplicationTerms, isHolidayEnabled,
holidays, workingDays);
@@ -725,6 +753,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
return installments;
}
/**
* Method to identify which transaction did the payment for current
* installment
*/
private void applyRest(List<LoanTransaction> loanTransactions, LocalDate from, LocalDate to,
LoanRepaymentScheduleInstallment installment,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, MonetaryCurrency currency,
@@ -760,6 +792,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
return nextScheduleDate;
}
/**
* Method returns the amount payable to close the loan account as of today.
*/
@Override
public Money fetchPrepaymentAmount(final List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency,
final LoanApplicationTerms applicationTerms, final MathContext mc) {
@@ -5,8 +5,11 @@
*/
package org.mifosplatform.portfolio.loanaccount.service;
import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
import org.mifosplatform.portfolio.loanaccount.data.LoanScheduleAccrualData;
public interface LoanAccrualWritePlatformService {
@@ -17,4 +20,6 @@ public interface LoanAccrualWritePlatformService {
String addPeriodicAccruals(LocalDate tilldate);
String addPeriodicAccruals(LocalDate tilldate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas);
}
@@ -95,7 +95,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
return addPeriodicAccruals(tilldate, loanScheduleAccrualDatas);
}
private String addPeriodicAccruals(final LocalDate tilldate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas) {
@Override
public String addPeriodicAccruals(final LocalDate tilldate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas) {
StringBuilder sb = new StringBuilder();
Set<Long> loansIds = new HashSet<>();
LocalDate accruredTill = null;
@@ -129,16 +130,18 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
private void addAccrualTillSpecificDate(final LocalDate tilldate, final LoanScheduleAccrualData accrualData,
final LocalDate accruredTill) throws Exception {
LocalDate interestStartDate = accrualData.getFromDateAsLocaldate();
LocalDate interestStartDate = accrualData.getFromDateAsLocaldate();
boolean isInterestStartDateEqulsInstallmentStartdate = true;
if (accrualData.getInterestCalculatedFrom() != null
&& accrualData.getFromDateAsLocaldate().isBefore(accrualData.getInterestCalculatedFrom())) {
isInterestStartDateEqulsInstallmentStartdate = false;
if (accrualData.getInterestCalculatedFrom().isBefore(accrualData.getDueDateAsLocaldate())) {
interestStartDate = accrualData.getInterestCalculatedFrom();
} else {
interestStartDate = accrualData.getDueDateAsLocaldate();
}
}
int totalNumberOfDays = Days.daysBetween(interestStartDate, accrualData.getDueDateAsLocaldate()).getDays();
LocalDate startDate = accruredTill;
if (startDate == null) {
@@ -156,10 +159,16 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
int daysInSchedule = Days.daysBetween(interestStartDate, tilldate).getDays();
switch (accrualData.getRepaymentFrequency()) {
case MONTHS:
totalNumberOfDays = calculateTotalNumberOfDaysForMonth(totalNumberOfDays, accrualData);
int numberOfDaysInMonth = calculateTotalNumberOfDaysForMonth(totalNumberOfDays, accrualData);
if (!(!isInterestStartDateEqulsInstallmentStartdate && totalNumberOfDays < numberOfDaysInMonth)) {
totalNumberOfDays = numberOfDaysInMonth;
}
break;
case YEARS:
totalNumberOfDays = calculateTotalNumberOfDaysForYear(totalNumberOfDays, accrualData);
int numberOfDaysinYear = calculateTotalNumberOfDaysForYear(totalNumberOfDays, accrualData);
if (!(!isInterestStartDateEqulsInstallmentStartdate && totalNumberOfDays < numberOfDaysinYear)) {
totalNumberOfDays = numberOfDaysinYear;
}
break;
default:
break;
@@ -1424,6 +1424,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
.append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,")
.append("loan.accrued_till as accruedTill, loan.repayment_period_frequency_enum as frequencyEnum, ")
.append("loan.interest_calculated_from_date as interestCalculatedFrom, ")
.append("loan.days_in_month_enum as daysInMonth, ")
.append("loan.days_in_year_enum as daysInYear, ")
.append("loan.repay_every as repayEvery,")
.append("(select sum(lc.amount) as dueamount from m_loan_charge lc where lc.loan_id = loan.id and lc.is_active = 1 and lc.waived = 0 and lc.is_penalty = 0 and lc.due_for_collection_as_of_date > ls.fromdate and lc.due_for_collection_as_of_date<= if(:tilldate < ls.duedate, :tilldate , ls.duedate)) as feedueIn,")
.append("(select sum(lc.amount) as dueamount from m_loan_charge lc where lc.loan_id = loan.id and lc.is_active = 1 and lc.waived = 0 and lc.is_penalty = 1 and lc.due_for_collection_as_of_date > ls.fromdate and lc.due_for_collection_as_of_date<= if(:tilldate < ls.duedate, :tilldate , ls.duedate)) as penalitydueIn,")
@@ -1448,8 +1450,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Long officeId = rs.getLong("officeId");
final LocalDate accruedTill = JdbcSupport.getLocalDate(rs, "accruedTill");
final LocalDate interestCalculatedFrom = JdbcSupport.getLocalDate(rs, "interestCalculatedFrom");
final Integer numberOfDaysInMonth = 30;
final Integer numberOfDaysInYear = 360;
final Integer numberOfDaysInMonth = JdbcSupport.getInteger(rs, "daysInMonth");;
final Integer numberOfDaysInYear = JdbcSupport.getInteger(rs, "daysInYear");;
final Integer frequencyEnum = JdbcSupport.getInteger(rs, "frequencyEnum");
final Integer repayEvery = JdbcSupport.getInteger(rs, "repayEvery");
final PeriodFrequencyType frequency = PeriodFrequencyType.fromInt(frequencyEnum);
@@ -315,6 +315,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
final Set<LoanCharge> loanCharges = loan.charges();
@@ -340,7 +341,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
updateRecurringCalendarDatesForInterestRecalculation(loan);
this.loanAccountDomainService.recalculateAccruals(loan);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(loan.getId()) //
@@ -526,7 +527,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
}
updateRecurringCalendarDatesForInterestRecalculation(loan);
this.loanAccountDomainService.recalculateAccruals(loan);
}
return changes;
}
@@ -766,6 +769,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
this.loanAccountDomainService.recalculateAccruals(loan);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(transactionId) //
@@ -857,7 +862,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
this.loanAccountDomainService.recalculateAccruals(loan);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(waiveInterestTransaction.getId()) //
@@ -925,7 +930,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
this.loanAccountDomainService.recalculateAccruals(loan);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(writeoff.getId()) //
@@ -998,7 +1003,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (possibleClosingTransaction != null) {
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
this.loanAccountDomainService.recalculateAccruals(loan);
CommandProcessingResult result = null;
if (possibleClosingTransaction != null) {
@@ -2043,6 +2048,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
saveLoanWithDataIntegrityViolationChecks(loan);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
this.loanAccountDomainService.recalculateAccruals(loan);
return new CommandProcessingResultBuilder() //
.withOfficeId(loan.getOfficeId()) //
.withClientId(loan.getClientId()) //
@@ -2091,7 +2097,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
this.loanAccountDomainService.recalculateAccruals(loan);
return new CommandProcessingResultBuilder() //
.withOfficeId(loan.getOfficeId()) //
.withClientId(loan.getClientId()) //
@@ -2205,8 +2211,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
workingDays = this.workingDaysRepository.findOne();
}
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(loanScheduleFactory, applicationCurrency,
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance,
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(loanScheduleFactory,
applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance,
existingTransactionIds, existingReversedTransactionIds);
saveLoanWithDataIntegrityViolationChecks(loan);
@@ -2218,6 +2224,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
this.loanAccountDomainService.recalculateAccruals(loan);
}
private void updateLoanTransaction(final Long loanTransactionId, final LoanTransaction newLoanTransaction) {