Merge pull request #1086 from pramodn02/develop

MIFOSX-1557 : corrected journal entries for advanced accounting with acc...
This commit is contained in:
Vishwas Babu A J
2014-09-26 19:21:26 -07:00
11 changed files with 406 additions and 120 deletions
@@ -237,6 +237,67 @@ public class AccountingProcessorHelper {
loanId, transactionId, transactionDate, amount); loanId, transactionId, transactionDate, amount);
} }
/**
* Convenience method that creates a pair of related Debits and Credits for
* Accrual Based accounting.
*
* The target accounts for debits and credits are switched in case of a
* reversal
*
* @param office
* @param accountTypeToBeDebited
* Enum of the placeholder GLAccount to be debited
* @param accountTypeToBeCredited
* Enum of the placeholder of the GLAccount to be credited
* @param loanProductId
* @param paymentTypeId
* @param loanId
* @param transactionId
* @param transactionDate
* @param amount
* @param isReversal
*/
public void createAccrualBasedJournalEntriesAndReversalsForLoanCharges(final Office office, final String currencyCode,
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long loanId,
final String transactionId, final Date transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
final List<ChargePaymentDTO> chargePaymentDTOs) {
GLAccount receivableAccount = getLinkedGLAccountForLoanCharges(loanProductId, accountTypeToBeDebited, null);
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
for (final ChargePaymentDTO chargePaymentDTO : chargePaymentDTOs) {
final Long chargeId = chargePaymentDTO.getChargeId();
final GLAccount chargeSpecificAccount = getLinkedGLAccountForLoanCharges(loanProductId, accountTypeToBeCredited, chargeId);
BigDecimal chargeSpecificAmount = chargePaymentDTO.getAmount();
// adjust net credit amount if the account is already present in the
// map
if (creditDetailsMap.containsKey(chargeSpecificAccount)) {
final BigDecimal existingAmount = creditDetailsMap.get(chargeSpecificAccount);
chargeSpecificAmount = chargeSpecificAmount.add(existingAmount);
}
creditDetailsMap.put(chargeSpecificAccount, chargeSpecificAmount);
}
BigDecimal totalCreditedAmount = BigDecimal.ZERO;
for (final Map.Entry<GLAccount, BigDecimal> entry : creditDetailsMap.entrySet()) {
final GLAccount account = entry.getKey();
final BigDecimal amount = entry.getValue();
totalCreditedAmount = totalCreditedAmount.add(amount);
if (isReversal) {
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
createCreditJournalEntryForLoan(office, currencyCode, receivableAccount, loanId, transactionId, transactionDate, amount);
} else {
createDebitJournalEntryForLoan(office, currencyCode, receivableAccount, loanId, transactionId, transactionDate, amount);
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
}
}
if (totalAmount.compareTo(totalCreditedAmount) != 0) { throw new PlatformDataIntegrityException(
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
totalCreditedAmount, totalAmount); }
}
/** /**
* Convenience method that creates a pair of related Debits and Credits for * Convenience method that creates a pair of related Debits and Credits for
* Cash Based accounting. * Cash Based accounting.
@@ -294,15 +294,17 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
} }
// create journal entries for the fees application (or reversal) // create journal entries for the fees application (or reversal)
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) { if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, this.helper.createAccrualBasedJournalEntriesAndReversalsForLoanCharges(office, currencyCode,
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(),
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, feesAmount, isReversed); loanProductId, loanId, transactionId, transactionDate, feesAmount, isReversed, loanTransactionDTO.getFeePayments());
} }
// create journal entries for the penalties application (or reversal) // create journal entries for the penalties application (or reversal)
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode,
this.helper.createAccrualBasedJournalEntriesAndReversalsForLoanCharges(office, currencyCode,
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(),
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversed); loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, isReversed,
loanTransactionDTO.getPenaltyPayments());
} }
} }
@@ -63,9 +63,10 @@ public class LoanChargeData {
private final BigDecimal maxCap; private final BigDecimal maxCap;
@SuppressWarnings("unused")
private final Collection<LoanInstallmentChargeData> installmentChargeData; private final Collection<LoanInstallmentChargeData> installmentChargeData;
private BigDecimal amountAccrued;
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) { public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null, null, return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null, null,
null, null, null); null, null, null);
@@ -124,6 +125,7 @@ public class LoanChargeData {
this.chargePayable = isChargePayable(); this.chargePayable = isChargePayable();
this.loanId = loanId; this.loanId = loanId;
this.installmentChargeData = installmentChargeData; this.installmentChargeData = installmentChargeData;
this.amountAccrued = null;
} }
private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount, private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
@@ -166,6 +168,7 @@ public class LoanChargeData {
this.minCap = minCap; this.minCap = minCap;
this.maxCap = maxCap; this.maxCap = maxCap;
this.installmentChargeData = installmentChargeData; this.installmentChargeData = installmentChargeData;
this.amountAccrued = null;
} }
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOutstanding, EnumOptionData chargeTimeType, public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOutstanding, EnumOptionData chargeTimeType,
@@ -195,6 +198,37 @@ public class LoanChargeData {
this.minCap = null; this.minCap = null;
this.maxCap = null; this.maxCap = null;
this.installmentChargeData = installmentChargeData; this.installmentChargeData = installmentChargeData;
this.amountAccrued = null;
}
public LoanChargeData(final Long id, final Long chargeId, final LocalDate dueAsOfDate, EnumOptionData chargeTimeType,
final BigDecimal amount, final BigDecimal amountAccrued, final BigDecimal amountWaived, final boolean penalty) {
this.id = id;
this.chargeId = chargeId;
this.name = null;
this.currency = null;
this.amount = amount;
this.amountPaid = null;
this.amountWaived = amountWaived;
this.amountWrittenOff = null;
this.amountOutstanding = null;
this.chargeTimeType = chargeTimeType;
this.dueDate = dueAsOfDate;
this.chargeCalculationType = null;
this.percentage = null;
this.amountPercentageAppliedTo = null;
this.penalty = penalty;
this.chargePaymentMode = null;
this.paid = false;
this.waived = false;
this.amountOrPercentage = null;
this.chargeOptions = null;
this.chargePayable = false;
this.loanId = null;
this.minCap = null;
this.maxCap = null;
this.installmentChargeData = null;
this.amountAccrued = amountAccrued;
} }
public LoanChargeData(LoanChargeData chargeData, Collection<LoanInstallmentChargeData> installmentChargeData) { public LoanChargeData(LoanChargeData chargeData, Collection<LoanInstallmentChargeData> installmentChargeData) {
@@ -223,6 +257,7 @@ public class LoanChargeData {
this.chargePayable = chargeData.chargePayable; this.chargePayable = chargeData.chargePayable;
this.loanId = chargeData.loanId; this.loanId = chargeData.loanId;
this.installmentChargeData = installmentChargeData; this.installmentChargeData = installmentChargeData;
this.amountAccrued = chargeData.amountAccrued;
} }
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOrPercentage) { public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOrPercentage) {
@@ -251,6 +286,7 @@ public class LoanChargeData {
this.minCap = null; this.minCap = null;
this.maxCap = null; this.maxCap = null;
this.installmentChargeData = null; this.installmentChargeData = null;
this.amountAccrued = null;
} }
public boolean isChargePayable() { public boolean isChargePayable() {
@@ -288,4 +324,33 @@ public class LoanChargeData {
public BigDecimal amountOrPercentage() { public BigDecimal amountOrPercentage() {
return this.amountOrPercentage; return this.amountOrPercentage;
} }
public Collection<LoanInstallmentChargeData> getInstallmentChargeData() {
return this.installmentChargeData;
}
public boolean isPenalty() {
return this.penalty;
}
public BigDecimal getAmount() {
return this.amount;
}
public BigDecimal getAmountAccrued() {
return this.amountAccrued;
}
public void updateAmountAccrued(BigDecimal amountAccrued) {
this.amountAccrued = amountAccrued;
}
public Long getChargeId() {
return this.chargeId;
}
public BigDecimal getAmountWaived() {
return this.amountWaived;
}
} }
@@ -13,20 +13,21 @@ public class LoanInstallmentChargeData {
private final Integer installmentNumber; private final Integer installmentNumber;
private final LocalDate dueDate; private final LocalDate dueDate;
@SuppressWarnings("unused")
private final BigDecimal amount; private final BigDecimal amount;
private final BigDecimal amountOutstanding; private final BigDecimal amountOutstanding;
private final BigDecimal amountWaived;
private final boolean paid; private final boolean paid;
private final boolean waived; private final boolean waived;
public LoanInstallmentChargeData(final Integer installmentNumber, final LocalDate dueDate, final BigDecimal amount, public LoanInstallmentChargeData(final Integer installmentNumber, final LocalDate dueDate, final BigDecimal amount,
final BigDecimal amountOutstanding, final boolean paid, final boolean waived) { final BigDecimal amountOutstanding, BigDecimal amountWaived, final boolean paid, final boolean waived) {
this.installmentNumber = installmentNumber; this.installmentNumber = installmentNumber;
this.dueDate = dueDate; this.dueDate = dueDate;
this.amount = amount; this.amount = amount;
this.amountOutstanding = amountOutstanding; this.amountOutstanding = amountOutstanding;
this.paid = paid; this.paid = paid;
this.waived = waived; this.waived = waived;
this.amountWaived = amountWaived;
} }
public Integer getInstallmentNumber() { public Integer getInstallmentNumber() {
@@ -45,4 +46,12 @@ public class LoanInstallmentChargeData {
return this.amountOutstanding; return this.amountOutstanding;
} }
public BigDecimal getAmount() {
return this.amount;
}
public BigDecimal getAmountWaived() {
return this.amountWaived;
}
} }
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.Map;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
@@ -19,8 +20,7 @@ public class LoanScheduleAccrualData {
private final LocalDate accruedTill; private final LocalDate accruedTill;
private final PeriodFrequencyType repaymentFrequency; private final PeriodFrequencyType repaymentFrequency;
private final Integer repayEvery; private final Integer repayEvery;
private final Integer numberOfDaysInYear; private final Integer installmentNumber;
private final Integer numberOfDaysInMonth;
private final LocalDate dueDate; private final LocalDate dueDate;
private final LocalDate fromDate; private final LocalDate fromDate;
private final Long repaymentScheduleId; private final Long repaymentScheduleId;
@@ -32,22 +32,21 @@ public class LoanScheduleAccrualData {
private final BigDecimal accruedFeeIncome; private final BigDecimal accruedFeeIncome;
private final BigDecimal accruedPenaltyIncome; private final BigDecimal accruedPenaltyIncome;
private final CurrencyData currencyData; private final CurrencyData currencyData;
private final BigDecimal dueDateFeeIncome;
private final BigDecimal dueDatePenaltyIncome;
private final LocalDate interestCalculatedFrom; private final LocalDate interestCalculatedFrom;
public LoanScheduleAccrualData(final Long loanId, final Long officeId, final LocalDate accruedTill, final Integer numberOfDaysInMonth, private Map<LoanChargeData, BigDecimal> applicableCharges;
final Integer numberOfDaysInYear, final PeriodFrequencyType repaymentFrequency, final Integer repayEvery, private BigDecimal dueDateFeeIncome;
final LocalDate dueDate, final LocalDate fromDate, final Long repaymentScheduleId, final Long loanProductId, private BigDecimal dueDatePenaltyIncome;
final BigDecimal interestIncome, final BigDecimal feeIncome, final BigDecimal penaltyIncome,
final BigDecimal accruedInterestIncome, final BigDecimal accruedFeeIncome, final BigDecimal accruedPenaltyIncome, public LoanScheduleAccrualData(final Long loanId, final Long officeId, final Integer installmentNumber, final LocalDate accruedTill,
final CurrencyData currencyData, final BigDecimal dueDateFeeIncome, final BigDecimal dueDatePenaltyIncome, final PeriodFrequencyType repaymentFrequency, final Integer repayEvery, final LocalDate dueDate, final LocalDate fromDate,
final LocalDate interestCalculatedFrom) { final Long repaymentScheduleId, final Long loanProductId, final BigDecimal interestIncome, final BigDecimal feeIncome,
final BigDecimal penaltyIncome, final BigDecimal accruedInterestIncome, final BigDecimal accruedFeeIncome,
final BigDecimal accruedPenaltyIncome, final CurrencyData currencyData, final LocalDate interestCalculatedFrom) {
this.loanId = loanId; this.loanId = loanId;
this.installmentNumber = installmentNumber;
this.officeId = officeId; this.officeId = officeId;
this.accruedTill = accruedTill; this.accruedTill = accruedTill;
this.numberOfDaysInMonth = numberOfDaysInMonth;
this.numberOfDaysInYear = numberOfDaysInYear;
this.dueDate = dueDate; this.dueDate = dueDate;
this.fromDate = fromDate; this.fromDate = fromDate;
this.repaymentScheduleId = repaymentScheduleId; this.repaymentScheduleId = repaymentScheduleId;
@@ -61,8 +60,6 @@ public class LoanScheduleAccrualData {
this.currencyData = currencyData; this.currencyData = currencyData;
this.repaymentFrequency = repaymentFrequency; this.repaymentFrequency = repaymentFrequency;
this.repayEvery = repayEvery; this.repayEvery = repayEvery;
this.dueDateFeeIncome = dueDateFeeIncome;
this.dueDatePenaltyIncome = dueDatePenaltyIncome;
this.interestCalculatedFrom = interestCalculatedFrom; this.interestCalculatedFrom = interestCalculatedFrom;
} }
@@ -122,14 +119,6 @@ public class LoanScheduleAccrualData {
return this.accruedTill; return this.accruedTill;
} }
public Integer getNumberOfDaysInYear() {
return this.numberOfDaysInYear;
}
public Integer getNumberOfDaysInMonth() {
return this.numberOfDaysInMonth;
}
public LocalDate getFromDateAsLocaldate() { public LocalDate getFromDateAsLocaldate() {
return this.fromDate; return this.fromDate;
} }
@@ -142,6 +131,18 @@ public class LoanScheduleAccrualData {
return this.repayEvery; return this.repayEvery;
} }
public LocalDate getInterestCalculatedFrom() {
return this.interestCalculatedFrom;
}
public Integer getInstallmentNumber() {
return this.installmentNumber;
}
public Map<LoanChargeData, BigDecimal> getApplicableCharges() {
return this.applicableCharges;
}
public BigDecimal getDueDateFeeIncome() { public BigDecimal getDueDateFeeIncome() {
return this.dueDateFeeIncome; return this.dueDateFeeIncome;
} }
@@ -150,9 +151,11 @@ public class LoanScheduleAccrualData {
return this.dueDatePenaltyIncome; return this.dueDatePenaltyIncome;
} }
public void updateChargeDetails(final Map<LoanChargeData, BigDecimal> applicableCharges, final BigDecimal dueDateFeeIncome,
public LocalDate getInterestCalculatedFrom() { final BigDecimal dueDatePenaltyIncome) {
return this.interestCalculatedFrom; this.applicableCharges = applicableCharges;
this.dueDateFeeIncome = dueDateFeeIncome;
this.dueDatePenaltyIncome = dueDatePenaltyIncome;
} }
} }
@@ -592,6 +592,9 @@ public class Loan extends AbstractPersistable<Long> {
final LoanTransaction applyLoanChargeTransaction = LoanTransaction.accrueLoanCharge(this, getOffice(), chargeAmount, final LoanTransaction applyLoanChargeTransaction = LoanTransaction.accrueLoanCharge(this, getOffice(), chargeAmount,
transactionDate, feeCharges, penaltyCharges); transactionDate, feeCharges, penaltyCharges);
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(applyLoanChargeTransaction, loanCharge, loanCharge.getAmount(
getCurrency()).getAmount());
applyLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy);
this.loanTransactions.add(applyLoanChargeTransaction); this.loanTransactions.add(applyLoanChargeTransaction);
return applyLoanChargeTransaction; return applyLoanChargeTransaction;
} }
@@ -40,8 +40,6 @@ import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
import org.mifosplatform.portfolio.calendar.service.CalendarUtils; import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; 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.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.group.domain.Group; import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException; import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
@@ -414,8 +412,12 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
return calculatedRepaymentsStartingFromDate; return calculatedRepaymentsStartingFromDate;
} }
/* (non-Javadoc) /*
* @see org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService#recalculateAccruals(org.mifosplatform.portfolio.loanaccount.domain.Loan) * (non-Javadoc)
*
* @see
* org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService
* #recalculateAccruals(org.mifosplatform.portfolio.loanaccount.domain.Loan)
*/ */
@Override @Override
public void recalculateAccruals(Loan loan) { public void recalculateAccruals(Loan loan) {
@@ -424,8 +426,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = new ArrayList<>(); Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = new ArrayList<>();
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments(); List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
Long loanId = loan.getId(); Long loanId = loan.getId();
DaysInMonthType daysInMonth = loan.repaymentScheduleDetail().fetchDaysInMonthType();
DaysInYearType daysInYear = loan.repaymentScheduleDetail().fetchDaysInYearType();
Long officeId = loan.getOfficeId(); Long officeId = loan.getOfficeId();
LocalDate accrualStartDate = null; LocalDate accrualStartDate = null;
PeriodFrequencyType repaymentFrequency = loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType(); PeriodFrequencyType repaymentFrequency = loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType();
@@ -459,12 +459,11 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
} }
} }
} }
LoanScheduleAccrualData accrualData = new LoanScheduleAccrualData(loanId, officeId, accrualStartDate, LoanScheduleAccrualData accrualData = new LoanScheduleAccrualData(loanId, officeId, installment.getInstallmentNumber(),
daysInMonth.getValue(), daysInYear.getValue(), repaymentFrequency, repayEvery, installment.getDueDate(), accrualStartDate, repaymentFrequency, repayEvery, installment.getDueDate(), installment.getFromDate(),
installment.getFromDate(), installment.getId(), loanProductId, installment.getId(), loanProductId, installment.getInterestCharged(currency).getAmount(), installment
installment.getInterestCharged(currency).getAmount(), installment.getFeeChargesCharged(currency).getAmount(), .getFeeChargesCharged(currency).getAmount(), installment.getPenaltyChargesCharged(currency).getAmount(),
installment.getPenaltyChargesCharged(currency).getAmount(), accruedInterestIncome, accruedFeeIncome, accruedInterestIncome, accruedFeeIncome, accruedPenaltyIncome, currencyData, interestCalculatedFrom);
accruedPenaltyIncome, currencyData, dueDateFeeIncome, dueDatePenaltyIncome, interestCalculatedFrom);
loanScheduleAccrualDatas.add(accrualData); loanScheduleAccrualDatas.add(accrualData);
} }
@@ -9,6 +9,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@@ -24,6 +25,8 @@ import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
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.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanScheduleAccrualData; import org.mifosplatform.portfolio.loanaccount.data.LoanScheduleAccrualData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
@@ -40,6 +43,7 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlatformService { public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlatformService {
private final LoanReadPlatformService loanReadPlatformService; private final LoanReadPlatformService loanReadPlatformService;
private final LoanChargeReadPlatformService loanChargeReadPlatformService;
private final JdbcTemplate jdbcTemplate; private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource; private final DataSource dataSource;
private final JournalEntryWritePlatformService journalEntryWritePlatformService; private final JournalEntryWritePlatformService journalEntryWritePlatformService;
@@ -47,12 +51,14 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
@Autowired @Autowired
public LoanAccrualWritePlatformServiceImpl(final RoutingDataSource dataSource, final LoanReadPlatformService loanReadPlatformService, public LoanAccrualWritePlatformServiceImpl(final RoutingDataSource dataSource, final LoanReadPlatformService loanReadPlatformService,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final JpaTransactionManager transactionManager) { final JournalEntryWritePlatformService journalEntryWritePlatformService, final JpaTransactionManager transactionManager,
final LoanChargeReadPlatformService loanChargeReadPlatformService) {
this.loanReadPlatformService = loanReadPlatformService; this.loanReadPlatformService = loanReadPlatformService;
this.dataSource = dataSource; this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(this.dataSource); this.jdbcTemplate = new JdbcTemplate(this.dataSource);
this.journalEntryWritePlatformService = journalEntryWritePlatformService; this.journalEntryWritePlatformService = journalEntryWritePlatformService;
this.transactionManager = transactionManager; this.transactionManager = transactionManager;
this.loanChargeReadPlatformService = loanChargeReadPlatformService;
} }
@Override @Override
@@ -61,9 +67,17 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = this.loanReadPlatformService.retriveScheduleAccrualData(); Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = this.loanReadPlatformService.retriveScheduleAccrualData();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
Set<Long> loansIds = new HashSet<>(); Set<Long> loansIds = new HashSet<>();
Map<Long, Collection<LoanChargeData>> loanChargeMap = new HashMap<>();
for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) { for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) {
try { try {
if (!loansIds.contains(accrualData.getLoanId())) { if (!loansIds.contains(accrualData.getLoanId())) {
if (!loanChargeMap.containsKey(accrualData.getLoanId())) {
Collection<LoanChargeData> chargeData = this.loanChargeReadPlatformService
.retrieveLoanChargesForAccural(accrualData.getLoanId());
loanChargeMap.put(accrualData.getLoanId(), chargeData);
}
updateCharges(loanChargeMap.get(accrualData.getLoanId()), accrualData, accrualData.getFromDateAsLocaldate(),
accrualData.getDueDateAsLocaldate());
addAccrualAccounting(accrualData); addAccrualAccounting(accrualData);
} }
} catch (Exception e) { } catch (Exception e) {
@@ -99,17 +113,27 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
Set<Long> loansIds = new HashSet<>(); Set<Long> loansIds = new HashSet<>();
LocalDate accruredTill = null; LocalDate accruredTill = null;
Long lastLoanId = null; Long lastLoanId = null;
Map<Long, Collection<LoanChargeData>> loanChargeMap = new HashMap<>();
for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) { for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) {
try { try {
if (!loansIds.contains(accrualData.getLoanId())) { if (!loansIds.contains(accrualData.getLoanId())) {
if (!loanChargeMap.containsKey(accrualData.getLoanId())) {
Collection<LoanChargeData> chargeData = this.loanChargeReadPlatformService
.retrieveLoanChargesForAccural(accrualData.getLoanId());
loanChargeMap.put(accrualData.getLoanId(), chargeData);
}
if (accrualData.getDueDateAsLocaldate().isAfter(tilldate)) { if (accrualData.getDueDateAsLocaldate().isAfter(tilldate)) {
if (accruredTill == null || lastLoanId == null || !lastLoanId.equals(accrualData.getLoanId())) { if (accruredTill == null || lastLoanId == null || !lastLoanId.equals(accrualData.getLoanId())) {
accruredTill = accrualData.getAccruedTill(); accruredTill = accrualData.getAccruedTill();
} }
if (accruredTill == null || accruredTill.isBefore(tilldate)) { if (accruredTill == null || accruredTill.isBefore(tilldate)) {
updateCharges(loanChargeMap.get(accrualData.getLoanId()), accrualData, accrualData.getFromDateAsLocaldate(),
tilldate);
addAccrualTillSpecificDate(tilldate, accrualData, accruredTill); addAccrualTillSpecificDate(tilldate, accrualData, accruredTill);
} }
} else { } else {
updateCharges(loanChargeMap.get(accrualData.getLoanId()), accrualData, accrualData.getFromDateAsLocaldate(),
accrualData.getDueDateAsLocaldate());
addAccrualAccounting(accrualData); addAccrualAccounting(accrualData);
accruredTill = accrualData.getDueDateAsLocaldate(); accruredTill = accrualData.getDueDateAsLocaldate();
} }
@@ -131,10 +155,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
private void addAccrualTillSpecificDate(final LocalDate tilldate, final LoanScheduleAccrualData accrualData, private void addAccrualTillSpecificDate(final LocalDate tilldate, final LoanScheduleAccrualData accrualData,
final LocalDate accruredTill) throws Exception { final LocalDate accruredTill) throws Exception {
LocalDate interestStartDate = accrualData.getFromDateAsLocaldate(); LocalDate interestStartDate = accrualData.getFromDateAsLocaldate();
// boolean isInterestStartDateEqulsInstallmentStartdate = true;
if (accrualData.getInterestCalculatedFrom() != null if (accrualData.getInterestCalculatedFrom() != null
&& accrualData.getFromDateAsLocaldate().isBefore(accrualData.getInterestCalculatedFrom())) { && accrualData.getFromDateAsLocaldate().isBefore(accrualData.getInterestCalculatedFrom())) {
// isInterestStartDateEqulsInstallmentStartdate = false;
if (accrualData.getInterestCalculatedFrom().isBefore(accrualData.getDueDateAsLocaldate())) { if (accrualData.getInterestCalculatedFrom().isBefore(accrualData.getDueDateAsLocaldate())) {
interestStartDate = accrualData.getInterestCalculatedFrom(); interestStartDate = accrualData.getInterestCalculatedFrom();
} else { } else {
@@ -155,21 +177,6 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
} }
} }
int daysToBeAccrued = Days.daysBetween(startDate, tilldate).getDays(); int daysToBeAccrued = Days.daysBetween(startDate, tilldate).getDays();
// if (daysToBeAccrued < 1) { return; }
// int daysInSchedule = Days.daysBetween(interestStartDate, tilldate).getDays();
/*
* switch (accrualData.getRepaymentFrequency()) { case MONTHS: int
* numberOfDaysInMonth =
* calculateTotalNumberOfDaysForMonth(totalNumberOfDays, accrualData);
* if (!(!isInterestStartDateEqulsInstallmentStartdate &&
* totalNumberOfDays < numberOfDaysInMonth)) { totalNumberOfDays =
* numberOfDaysInMonth; } break; case YEARS: int numberOfDaysinYear =
* calculateTotalNumberOfDaysForYear(totalNumberOfDays, accrualData); if
* (!(!isInterestStartDateEqulsInstallmentStartdate && totalNumberOfDays
* < numberOfDaysinYear)) { totalNumberOfDays = numberOfDaysinYear; }
* break; default: break; }
*/
double interestPerDay = accrualData.getInterestIncome().doubleValue() / totalNumberOfDays; double interestPerDay = accrualData.getInterestIncome().doubleValue() / totalNumberOfDays;
BigDecimal amount = BigDecimal.ZERO; BigDecimal amount = BigDecimal.ZERO;
BigDecimal interestportion = null; BigDecimal interestportion = null;
@@ -182,23 +189,22 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
interestportion = BigDecimal.valueOf(iterest); interestportion = BigDecimal.valueOf(iterest);
} }
interestportion = interestportion.setScale(accrualData.getCurrencyData().decimalPlaces(), RoundingMode.HALF_EVEN); interestportion = interestportion.setScale(accrualData.getCurrencyData().decimalPlaces(), RoundingMode.HALF_EVEN);
amount = amount.add(interestportion);
BigDecimal totalAccInterest = accrualData.getAccruedInterestIncome(); BigDecimal totalAccInterest = accrualData.getAccruedInterestIncome();
BigDecimal totalAccPenalty = accrualData.getAccruedPenaltyIncome(); BigDecimal totalAccPenalty = accrualData.getAccruedPenaltyIncome();
BigDecimal totalAccFee = accrualData.getAccruedFeeIncome(); BigDecimal totalAccFee = accrualData.getAccruedFeeIncome();
if (startDate.isEqual(accrualData.getFromDateAsLocaldate())) { if (interestportion != null) {
totalAccInterest = null; if (totalAccInterest == null) {
totalAccPenalty = null; totalAccInterest = BigDecimal.ZERO;
totalAccFee = null; }
interestportion = interestportion.subtract(totalAccInterest);
amount = amount.add(interestportion);
totalAccInterest = totalAccInterest.add(interestportion);
if (interestportion.compareTo(BigDecimal.ZERO) == 0) {
interestportion = null;
}
} }
if (totalAccInterest == null) {
totalAccInterest = BigDecimal.ZERO;
}
totalAccInterest = totalAccInterest.add(interestportion);
if (feeportion != null) { if (feeportion != null) {
if (totalAccFee == null) { if (totalAccFee == null) {
totalAccFee = BigDecimal.ZERO; totalAccFee = BigDecimal.ZERO;
@@ -228,24 +234,6 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
} }
} }
/*
* private int calculateTotalNumberOfDaysForMonth(final int
* totalNumberOfDays, final LoanScheduleAccrualData accrualData) { int
* numberOfDays = totalNumberOfDays; DaysInMonthType type =
* DaysInMonthType.fromInt(accrualData.getNumberOfDaysInMonth()); switch
* (type) { case DAYS_30: numberOfDays = 30 * accrualData.getRepayEvery();
* break; default: break; } return numberOfDays; }
*
* private int calculateTotalNumberOfDaysForYear(final int
* totalNumberOfDays, final LoanScheduleAccrualData accrualData) { int
* numberOfDays = totalNumberOfDays; DaysInYearType type =
* DaysInYearType.fromInt(accrualData.getNumberOfDaysInMonth()); switch
* (type) { case DAYS_360: numberOfDays = 360 * accrualData.getRepayEvery();
* break; case DAYS_364: numberOfDays = 364 * accrualData.getRepayEvery();
* break; case DAYS_365: numberOfDays = 365 * accrualData.getRepayEvery();
* break; default: break; } return numberOfDays; }
*/
@Transactional @Transactional
public void addAccrualAccounting(LoanScheduleAccrualData scheduleAccrualData) throws Exception { public void addAccrualAccounting(LoanScheduleAccrualData scheduleAccrualData) throws Exception {
@@ -306,6 +294,13 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
LoanTransactionType.ACCRUAL.getValue(), accruredTill.toDate(), amount, interestportion, feeportion, penaltyportion); LoanTransactionType.ACCRUAL.getValue(), accruredTill.toDate(), amount, interestportion, feeportion, penaltyportion);
final Long transactonId = this.jdbcTemplate.queryForLong("SELECT LAST_INSERT_ID()"); final Long transactonId = this.jdbcTemplate.queryForLong("SELECT LAST_INSERT_ID()");
Map<LoanChargeData, BigDecimal> applicableCharges = scheduleAccrualData.getApplicableCharges();
String chargespaidSql = "INSERT INTO m_loan_charge_paid_by (loan_transaction_id, loan_charge_id, amount) VALUES (?,?,?)";
for (Map.Entry<LoanChargeData, BigDecimal> entry : applicableCharges.entrySet()) {
LoanChargeData chargeData = entry.getKey();
this.jdbcTemplate.update(chargespaidSql, transactonId, chargeData.getId(), entry.getValue());
}
Map<String, Object> transactionMap = toMapData(transactonId, amount, interestportion, feeportion, penaltyportion, Map<String, Object> transactionMap = toMapData(transactonId, amount, interestportion, feeportion, penaltyportion,
scheduleAccrualData, accruredTill); scheduleAccrualData, accruredTill);
@@ -365,7 +360,86 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
thisTransactionData.put("penaltyChargesPortion", penaltyportion); thisTransactionData.put("penaltyChargesPortion", penaltyportion);
thisTransactionData.put("overPaymentPortion", null); thisTransactionData.put("overPaymentPortion", null);
Map<LoanChargeData, BigDecimal> applicableCharges = loanScheduleAccrualData.getApplicableCharges();
if (applicableCharges != null && !applicableCharges.isEmpty()) {
final List<Map<String, Object>> loanChargesPaidData = new ArrayList<>();
for (Map.Entry<LoanChargeData, BigDecimal> entry : applicableCharges.entrySet()) {
LoanChargeData chargeData = entry.getKey();
final Map<String, Object> loanChargePaidData = new LinkedHashMap<>();
loanChargePaidData.put("chargeId", chargeData.getChargeId());
loanChargePaidData.put("isPenalty", chargeData.isPenalty());
loanChargePaidData.put("loanChargeId", chargeData.getId());
loanChargePaidData.put("amount", entry.getValue());
loanChargesPaidData.add(loanChargePaidData);
}
thisTransactionData.put("loanChargesPaid", loanChargesPaidData);
}
return thisTransactionData; return thisTransactionData;
} }
private void updateCharges(final Collection<LoanChargeData> chargesData, final LoanScheduleAccrualData accrualData,
final LocalDate startDate, final LocalDate endDate) {
final Map<LoanChargeData, BigDecimal> applicableCharges = new HashMap<>();
BigDecimal dueDateFeeIncome = BigDecimal.ZERO;
BigDecimal dueDatePenaltyIncome = BigDecimal.ZERO;
for (LoanChargeData loanCharge : chargesData) {
BigDecimal chargeAmount = BigDecimal.ZERO;
if (loanCharge.getDueDate() == null) {
if (loanCharge.isInstallmentFee() && accrualData.getDueDateAsLocaldate().isEqual(endDate)) {
BigDecimal accruedAmount = BigDecimal.ZERO;
Collection<LoanInstallmentChargeData> installmentData = loanCharge.getInstallmentChargeData();
for (LoanInstallmentChargeData installmentChargeData : installmentData) {
BigDecimal accruableForInstallment = installmentChargeData.getAmount();
if (installmentChargeData.getAmountWaived() != null) {
accruableForInstallment = accruableForInstallment.subtract(installmentChargeData.getAmountWaived());
}
if (installmentChargeData.getInstallmentNumber().equals(accrualData.getInstallmentNumber())) {
chargeAmount = accruableForInstallment;
boolean canAddCharge = chargeAmount.compareTo(BigDecimal.ZERO) == 1;
if (canAddCharge
&& (loanCharge.getAmountAccrued() == null || loanCharge.getAmountAccrued().compareTo(accruedAmount) == 0)) {
applicableCharges.put(loanCharge, chargeAmount);
BigDecimal amountAccrued = chargeAmount;
if (loanCharge.getAmountAccrued() != null) {
amountAccrued = amountAccrued.add(loanCharge.getAmountAccrued());
}
loanCharge.updateAmountAccrued(amountAccrued);
}
break;
}
accruedAmount = accruedAmount.add(accruableForInstallment);
}
}
} else if (loanCharge.getDueDate().isAfter(startDate) && !loanCharge.getDueDate().isAfter(endDate)) {
chargeAmount = loanCharge.getAmount();
if (loanCharge.getAmountWaived() != null) {
chargeAmount = chargeAmount.subtract(loanCharge.getAmountWaived());
}
boolean canAddCharge = chargeAmount.compareTo(BigDecimal.ZERO) == 1;
if (canAddCharge && loanCharge.getAmountAccrued() == null) {
applicableCharges.put(loanCharge, chargeAmount);
}
}
if (loanCharge.isPenalty()) {
dueDatePenaltyIncome = dueDatePenaltyIncome.add(chargeAmount);
} else {
dueDateFeeIncome = dueDateFeeIncome.add(chargeAmount);
}
}
if (dueDateFeeIncome.compareTo(BigDecimal.ZERO) == 0) {
dueDateFeeIncome = null;
}
if (dueDatePenaltyIncome.compareTo(BigDecimal.ZERO) == 0) {
dueDatePenaltyIncome = null;
}
accrualData.updateChargeDetails(applicableCharges, dueDateFeeIncome, dueDatePenaltyIncome);
}
} }
@@ -24,4 +24,6 @@ public interface LoanChargeReadPlatformService {
Collection<LoanInstallmentChargeData> retrieveInstallmentLoanCharges(Long loanChargeId, boolean onlyPaymentPendingCharges); Collection<LoanInstallmentChargeData> retrieveInstallmentLoanCharges(Long loanChargeId, boolean onlyPaymentPendingCharges);
Collection<Integer> retrieveOverdueInstallmentChargeFrequencyNumber(Long loanId, Long chargeId, Integer periodNumber); Collection<Integer> retrieveOverdueInstallmentChargeFrequencyNumber(Long loanId, Long chargeId, Integer periodNumber);
Collection<LoanChargeData> retrieveLoanChargesForAccural(Long loanId);
} }
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -23,6 +24,7 @@ import org.mifosplatform.portfolio.charge.service.ChargeEnumerations;
import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService; import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData; import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData; import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
@@ -208,7 +210,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
public String schema() { public String schema() {
return " lsi.installment as installmentNumber, lsi.duedate as dueAsOfDate, " return " lsi.installment as installmentNumber, lsi.duedate as dueAsOfDate, "
+ "lic.amount_outstanding_derived as amountOutstanding," + "lic.amount as amount, " + "lic.is_paid_derived as paid, " + "lic.amount_outstanding_derived as amountOutstanding," + "lic.amount as amount, " + "lic.is_paid_derived as paid, "
+ "lic.waived as waied " + "from m_loan_installment_charge lic " + "lic.amount_waived_derived as amountWaived, " + "lic.waived as waied " + "from m_loan_installment_charge lic "
+ "join m_loan_repayment_schedule lsi on lsi.id = lic.loan_schedule_id "; + "join m_loan_repayment_schedule lsi on lsi.id = lic.loan_schedule_id ";
} }
@@ -218,10 +220,11 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate"); final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
final BigDecimal amountOutstanding = rs.getBigDecimal("amountOutstanding"); final BigDecimal amountOutstanding = rs.getBigDecimal("amountOutstanding");
final BigDecimal amount = rs.getBigDecimal("amount"); final BigDecimal amount = rs.getBigDecimal("amount");
final BigDecimal amountWaived = rs.getBigDecimal("amountWaived");
final boolean paid = rs.getBoolean("paid"); final boolean paid = rs.getBoolean("paid");
final boolean waived = rs.getBoolean("waied"); final boolean waived = rs.getBoolean("waied");
return new LoanInstallmentChargeData(installmentNumber, dueAsOfDate, amount, amountOutstanding, paid, waived); return new LoanInstallmentChargeData(installmentNumber, dueAsOfDate, amount, amountOutstanding, amountWaived, paid, waived);
} }
} }
@@ -237,4 +240,80 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
} }
return this.jdbcTemplate.queryForList(sql, Integer.class, params); return this.jdbcTemplate.queryForList(sql, Integer.class, params);
} }
@Override
public Collection<LoanChargeData> retrieveLoanChargesForAccural(final Long loanId) {
final LoanChargeAccrualMapper rm = new LoanChargeAccrualMapper();
final String sql = "select " + rm.schema() + " where lc.loan_id=? AND lc.is_active = 1 group by lc.id "
+ " order by lc.charge_time_enum ASC, lc.due_for_collection_as_of_date ASC, lc.is_penalty ASC";
Collection<LoanChargeData> charges = this.jdbcTemplate.query(sql, rm,
new Object[] { LoanTransactionType.ACCRUAL.getValue(), loanId });
Collection<LoanChargeData> removeCharges = new ArrayList<>();
for (LoanChargeData loanChargeData : charges) {
if (loanChargeData.isInstallmentFee()) {
removeCharges.add(loanChargeData);
}
}
charges.removeAll(removeCharges);
for (LoanChargeData loanChargeData : removeCharges) {
if (loanChargeData.isInstallmentFee()) {
Collection<LoanInstallmentChargeData> installmentChargeDatas = retrieveInstallmentLoanCharges(loanChargeData.getId(), false);
LoanChargeData modifiedChargeData = new LoanChargeData(loanChargeData, installmentChargeDatas);
charges.add(modifiedChargeData);
}
}
return charges;
}
private static final class LoanChargeAccrualMapper implements RowMapper<LoanChargeData> {
private final String schemaSql;
public LoanChargeAccrualMapper() {
StringBuilder sb = new StringBuilder(50);
sb.append("lc.id as id, lc.charge_id as chargeId, ");
sb.append("lc.amount as amountDue, ");
sb.append("lc.amount_waived_derived as amountWaived, ");
sb.append("lc.charge_time_enum as chargeTime, ");
sb.append(" sum(cp.amount) as amountAccrued, ");
sb.append("lc.is_penalty as penalty, ");
sb.append("lc.due_for_collection_as_of_date as dueAsOfDate ");
sb.append(" from m_loan_charge lc ");
sb.append("left join (");
sb.append("select lcp.loan_charge_id, lcp.amount");
sb.append(" from m_loan_charge_paid_by lcp ");
sb.append("inner join m_loan_transaction lt on lt.id = lcp.loan_transaction_id and lt.is_reversed = 0 and lt.transaction_type_enum = ?");
sb.append(") cp on cp.loan_charge_id= lc.id ");
schemaSql = sb.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public LoanChargeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long chargeId = rs.getLong("chargeId");
final BigDecimal amount = rs.getBigDecimal("amountDue");
final BigDecimal amountAccrued = rs.getBigDecimal("amountAccrued");
final BigDecimal amountWaived = rs.getBigDecimal("amountWaived");
final int chargeTime = rs.getInt("chargeTime");
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime);
final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
final boolean penalty = rs.getBoolean("penalty");
return new LoanChargeData(id, chargeId, dueAsOfDate, chargeTimeType, amount, amountAccrued, amountWaived, penalty);
}
}
} }
@@ -1448,11 +1448,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.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.accrued_till as accruedTill, loan.repayment_period_frequency_enum as frequencyEnum, ")
.append("loan.interest_calculated_from_date as interestCalculatedFrom, ") .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("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("ls.installment as installmentNumber, ")
.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,")
.append("ls.duedate as duedate,ls.fromdate as fromdate ,ls.id as scheduleId,loan.product_id as productId,") .append("ls.duedate as duedate,ls.fromdate as fromdate ,ls.id as scheduleId,loan.product_id as productId,")
.append("if(ls.interest_waived_derived is null,ls.interest_amount,(ls.interest_amount-ls.interest_waived_derived)) as interest,") .append("if(ls.interest_waived_derived is null,ls.interest_amount,(ls.interest_amount-ls.interest_waived_derived)) as interest,")
.append("if(ls.penalty_charges_waived_derived is null , ls.penalty_charges_amount,(ls.penalty_charges_amount-ls.penalty_charges_waived_derived)) as penalty,") .append("if(ls.penalty_charges_waived_derived is null , ls.penalty_charges_amount,(ls.penalty_charges_amount-ls.penalty_charges_waived_derived)) as penalty,")
@@ -1474,10 +1471,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Long officeId = rs.getLong("officeId"); final Long officeId = rs.getLong("officeId");
final LocalDate accruedTill = JdbcSupport.getLocalDate(rs, "accruedTill"); final LocalDate accruedTill = JdbcSupport.getLocalDate(rs, "accruedTill");
final LocalDate interestCalculatedFrom = JdbcSupport.getLocalDate(rs, "interestCalculatedFrom"); final LocalDate interestCalculatedFrom = JdbcSupport.getLocalDate(rs, "interestCalculatedFrom");
final Integer numberOfDaysInMonth = JdbcSupport.getInteger(rs, "daysInMonth"); final Integer installmentNumber = JdbcSupport.getInteger(rs, "installmentNumber");
;
final Integer numberOfDaysInYear = JdbcSupport.getInteger(rs, "daysInYear");
;
final Integer frequencyEnum = JdbcSupport.getInteger(rs, "frequencyEnum"); final Integer frequencyEnum = JdbcSupport.getInteger(rs, "frequencyEnum");
final Integer repayEvery = JdbcSupport.getInteger(rs, "repayEvery"); final Integer repayEvery = JdbcSupport.getInteger(rs, "repayEvery");
final PeriodFrequencyType frequency = PeriodFrequencyType.fromInt(frequencyEnum); final PeriodFrequencyType frequency = PeriodFrequencyType.fromInt(frequencyEnum);
@@ -1501,12 +1496,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf,
currencyDisplaySymbol, currencyNameCode); currencyDisplaySymbol, currencyNameCode);
final BigDecimal dueDateFeeIncome = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "feedueIn"); return new LoanScheduleAccrualData(loanId, officeId, installmentNumber, accruedTill, frequency, repayEvery, dueDate, fromDate,
final BigDecimal dueDatePenaltyIncome = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "penalitydueIn"); repaymentScheduleId, loanProductId, interestIncome, feeIncome, penaltyIncome, accruedInterestIncome, accruedFeeIncome,
return new LoanScheduleAccrualData(loanId, officeId, accruedTill, numberOfDaysInMonth, numberOfDaysInYear, frequency, accruedPenaltyIncome, currencyData, interestCalculatedFrom);
repayEvery, dueDate, fromDate, repaymentScheduleId, loanProductId, interestIncome, feeIncome, penaltyIncome,
accruedInterestIncome, accruedFeeIncome, accruedPenaltyIncome, currencyData, dueDateFeeIncome, dueDatePenaltyIncome,
interestCalculatedFrom);
} }
} }
@@ -1517,7 +1509,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final StringBuilder sqlBuilder = new StringBuilder(400); final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder sqlBuilder
.append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,") .append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,")
.append("ls.duedate as duedate,ls.id as scheduleId,loan.product_id as productId,") .append("ls.duedate as duedate,ls.fromdate as fromdate,ls.id as scheduleId,loan.product_id as productId,")
.append("ls.installment as installmentNumber, ")
.append("if(ls.interest_waived_derived is null,ls.interest_amount,(ls.interest_amount-ls.interest_waived_derived)) as interest,") .append("if(ls.interest_waived_derived is null,ls.interest_amount,(ls.interest_amount-ls.interest_waived_derived)) as interest,")
.append("if(ls.penalty_charges_waived_derived is null , ls.penalty_charges_amount,(ls.penalty_charges_amount-ls.penalty_charges_waived_derived)) as penalty,") .append("if(ls.penalty_charges_waived_derived is null , ls.penalty_charges_amount,(ls.penalty_charges_amount-ls.penalty_charges_waived_derived)) as penalty,")
.append("if(ls.fee_charges_waived_derived is null , ls.fee_charges_amount,(ls.fee_charges_amount-ls.fee_charges_waived_derived)) as charges,") .append("if(ls.fee_charges_waived_derived is null , ls.fee_charges_amount,(ls.fee_charges_amount-ls.fee_charges_waived_derived)) as charges,")
@@ -1536,7 +1529,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Long loanId = rs.getLong("loanId"); final Long loanId = rs.getLong("loanId");
final Long officeId = rs.getLong("officeId"); final Long officeId = rs.getLong("officeId");
final Integer installmentNumber = JdbcSupport.getInteger(rs, "installmentNumber");
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "duedate"); final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "duedate");
final LocalDate fromdate = JdbcSupport.getLocalDate(rs, "fromdate");
final Long repaymentScheduleId = rs.getLong("scheduleId"); final Long repaymentScheduleId = rs.getLong("scheduleId");
final Long loanProductId = rs.getLong("productId"); final Long loanProductId = rs.getLong("productId");
final BigDecimal interestIncome = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "interest"); final BigDecimal interestIncome = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "interest");
@@ -1555,18 +1550,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf,
currencyDisplaySymbol, currencyNameCode); currencyDisplaySymbol, currencyNameCode);
final LocalDate accruedTill = null; final LocalDate accruedTill = null;
final Integer numberOfDaysInMonth = null;
final Integer numberOfDaysInYear = null;
final PeriodFrequencyType frequency = null; final PeriodFrequencyType frequency = null;
final Integer repayEvery = null; final Integer repayEvery = null;
final LocalDate fromDate = null;
final BigDecimal dueDateFeeincome = null;
final BigDecimal dueDatePenaltyIncome = null;
final LocalDate interestCalculatedFrom = null; final LocalDate interestCalculatedFrom = null;
return new LoanScheduleAccrualData(loanId, officeId, accruedTill, numberOfDaysInMonth, numberOfDaysInYear, frequency, return new LoanScheduleAccrualData(loanId, officeId, installmentNumber, accruedTill, frequency, repayEvery, dueDate, fromdate,
repayEvery, dueDate, fromDate, repaymentScheduleId, loanProductId, interestIncome, feeIncome, penaltyIncome, repaymentScheduleId, loanProductId, interestIncome, feeIncome, penaltyIncome, accruedInterestIncome, accruedFeeIncome,
accruedInterestIncome, accruedFeeIncome, accruedPenaltyIncome, currencyData, dueDateFeeincome, dueDatePenaltyIncome, accruedPenaltyIncome, currencyData, interestCalculatedFrom);
interestCalculatedFrom);
} }
} }
@@ -1609,7 +1598,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(" group by ml.id"); sqlBuilder.append(" group by ml.id");
try { try {
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class,
new Object[] { LoanStatus.ACTIVE.getValue(), formatter.print(LocalDate.now()),formatter.print(LocalDate.now()) }); new Object[] { LoanStatus.ACTIVE.getValue(), formatter.print(LocalDate.now()), formatter.print(LocalDate.now()) });
} catch (final EmptyResultDataAccessException e) { } catch (final EmptyResultDataAccessException e) {
return null; return null;
} }