MIFOSX-1537 : added original schedule to history
This commit is contained in:
+20
@@ -0,0 +1,20 @@
|
|||||||
|
ALTER TABLE `m_loan_repayment_schedule_history`
|
||||||
|
DROP COLUMN `principal_completed_derived`,
|
||||||
|
DROP COLUMN `principal_writtenoff_derived`,
|
||||||
|
DROP COLUMN `interest_completed_derived`,
|
||||||
|
DROP COLUMN `interest_writtenoff_derived`,
|
||||||
|
DROP COLUMN `interest_waived_derived`,
|
||||||
|
DROP COLUMN `accrual_interest_derived`,
|
||||||
|
DROP COLUMN `fee_charges_completed_derived`,
|
||||||
|
DROP COLUMN `fee_charges_writtenoff_derived`,
|
||||||
|
DROP COLUMN `fee_charges_waived_derived`,
|
||||||
|
DROP COLUMN `accrual_fee_charges_derived`,
|
||||||
|
DROP COLUMN `penalty_charges_completed_derived`,
|
||||||
|
DROP COLUMN `penalty_charges_writtenoff_derived`,
|
||||||
|
DROP COLUMN `penalty_charges_waived_derived`,
|
||||||
|
DROP COLUMN `accrual_penalty_charges_derived`,
|
||||||
|
DROP COLUMN `total_paid_in_advance_derived`,
|
||||||
|
DROP COLUMN `total_paid_late_derived`,
|
||||||
|
DROP COLUMN `completed_derived`,
|
||||||
|
DROP COLUMN `obligations_met_on_date`,
|
||||||
|
ADD COLUMN `version` INT(5) NOT NULL;
|
||||||
+15
-3
@@ -77,6 +77,7 @@ import org.mifosplatform.portfolio.loanaccount.guarantor.service.GuarantorReadPl
|
|||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.service.LoanChargeReadPlatformService;
|
import org.mifosplatform.portfolio.loanaccount.service.LoanChargeReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
|
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||||
@@ -137,6 +138,7 @@ public class LoansApiResource {
|
|||||||
private final NoteReadPlatformServiceImpl noteReadPlatformService;
|
private final NoteReadPlatformServiceImpl noteReadPlatformService;
|
||||||
private final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService;
|
private final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService;
|
||||||
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||||
|
private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
|
public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
|
||||||
@@ -153,7 +155,8 @@ public class LoansApiResource {
|
|||||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||||
final CalendarReadPlatformService calendarReadPlatformService, final NoteReadPlatformServiceImpl noteReadPlatformService,
|
final CalendarReadPlatformService calendarReadPlatformService, final NoteReadPlatformServiceImpl noteReadPlatformService,
|
||||||
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformServiceImpl,
|
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformServiceImpl,
|
||||||
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService) {
|
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
|
||||||
|
final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanReadPlatformService = loanReadPlatformService;
|
this.loanReadPlatformService = loanReadPlatformService;
|
||||||
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
||||||
@@ -175,6 +178,7 @@ public class LoansApiResource {
|
|||||||
this.noteReadPlatformService = noteReadPlatformService;
|
this.noteReadPlatformService = noteReadPlatformService;
|
||||||
this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformServiceImpl;
|
this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformServiceImpl;
|
||||||
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
|
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
|
||||||
|
this.loanScheduleHistoryReadPlatformService = loanScheduleHistoryReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@@ -318,8 +322,8 @@ public class LoansApiResource {
|
|||||||
if (!associationParameters.isEmpty()) {
|
if (!associationParameters.isEmpty()) {
|
||||||
|
|
||||||
if (associationParameters.contains("all")) {
|
if (associationParameters.contains("all")) {
|
||||||
associationParameters.addAll(Arrays.asList("repaymentSchedule", "futureSchedule", "transactions", "charges", "guarantors",
|
associationParameters.addAll(Arrays.asList("repaymentSchedule", "futureSchedule", "originalSchedule", "transactions",
|
||||||
"collateral", "notes", "linkedAccount", "multiDisburseDetails"));
|
"charges", "guarantors", "collateral", "notes", "linkedAccount", "multiDisburseDetails"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (associationParameters.contains("guarantors")) {
|
if (associationParameters.contains("guarantors")) {
|
||||||
@@ -360,6 +364,14 @@ public class LoansApiResource {
|
|||||||
mandatoryResponseParameters.add("futureSchedule");
|
mandatoryResponseParameters.add("futureSchedule");
|
||||||
this.calculationPlatformService.updateFutureSchedule(repaymentSchedule, loanId);
|
this.calculationPlatformService.updateFutureSchedule(repaymentSchedule, loanId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (associationParameters.contains("originalSchedule") && loanBasicDetails.isInterestRecalculationEnabled()
|
||||||
|
&& loanBasicDetails.isInterestRecalculationEnabled()) {
|
||||||
|
mandatoryResponseParameters.add("originalSchedule");
|
||||||
|
LoanScheduleData loanScheduleData = this.loanScheduleHistoryReadPlatformService.retrieveRepaymentArchiveSchedule(
|
||||||
|
loanId, repaymentScheduleRelatedData, disbursementData);
|
||||||
|
loanBasicDetails = LoanAccountData.withOriginalSchedule(loanBasicDetails, loanScheduleData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (associationParameters.contains("charges")) {
|
if (associationParameters.contains("charges")) {
|
||||||
|
|||||||
+52
-16
@@ -115,6 +115,7 @@ public class LoanAccountData {
|
|||||||
private final CalendarData meeting;
|
private final CalendarData meeting;
|
||||||
private final Collection<NoteData> notes;
|
private final Collection<NoteData> notes;
|
||||||
private final Collection<DisbursementData> disbursementDetails;
|
private final Collection<DisbursementData> disbursementDetails;
|
||||||
|
private final LoanScheduleData originalSchedule;
|
||||||
// template
|
// template
|
||||||
private final Collection<LoanProductData> productOptions;
|
private final Collection<LoanProductData> productOptions;
|
||||||
private final Collection<StaffData> loanOfficerOptions;
|
private final Collection<StaffData> loanOfficerOptions;
|
||||||
@@ -260,6 +261,7 @@ public class LoanAccountData {
|
|||||||
final EnumOptionData daysInYearType = null;
|
final EnumOptionData daysInYearType = null;
|
||||||
final boolean isInterestRecalculationEnabled = false;
|
final boolean isInterestRecalculationEnabled = false;
|
||||||
final LoanInterestRecalculationData interestRecalculationData = null;
|
final LoanInterestRecalculationData interestRecalculationData = null;
|
||||||
|
final LoanScheduleData originalSchedule = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
@@ -275,7 +277,7 @@ public class LoanAccountData {
|
|||||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||||
disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations,
|
disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations,
|
||||||
product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
||||||
isInterestRecalculationEnabled, interestRecalculationData);
|
isInterestRecalculationEnabled, interestRecalculationData, originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -369,6 +371,7 @@ public class LoanAccountData {
|
|||||||
final EnumOptionData daysInYearType = null;
|
final EnumOptionData daysInYearType = null;
|
||||||
final boolean isInterestRecalculationEnabled = false;
|
final boolean isInterestRecalculationEnabled = false;
|
||||||
final LoanInterestRecalculationData interestRecalculationData = null;
|
final LoanInterestRecalculationData interestRecalculationData = null;
|
||||||
|
final LoanScheduleData originalSchedule = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
@@ -383,7 +386,7 @@ public class LoanAccountData {
|
|||||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
||||||
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount,
|
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount,
|
||||||
maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges,
|
maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges,
|
||||||
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData);
|
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
||||||
@@ -405,7 +408,8 @@ public class LoanAccountData {
|
|||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData);
|
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||||
|
acc.originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -500,6 +504,7 @@ public class LoanAccountData {
|
|||||||
final EnumOptionData daysInYearType = null;
|
final EnumOptionData daysInYearType = null;
|
||||||
final boolean isInterestRecalculationEnabled = false;
|
final boolean isInterestRecalculationEnabled = false;
|
||||||
final LoanInterestRecalculationData interestRecalculationData = null;
|
final LoanInterestRecalculationData interestRecalculationData = null;
|
||||||
|
final LoanScheduleData originalSchedule = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
@@ -514,7 +519,7 @@ public class LoanAccountData {
|
|||||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
||||||
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingBalance,
|
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingBalance,
|
||||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData);
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
||||||
@@ -535,7 +540,8 @@ public class LoanAccountData {
|
|||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData);
|
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||||
|
acc.originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
||||||
@@ -643,6 +649,7 @@ public class LoanAccountData {
|
|||||||
Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
||||||
final Boolean inArrears = null;
|
final Boolean inArrears = null;
|
||||||
final Boolean isNPA = null;
|
final Boolean isNPA = null;
|
||||||
|
final LoanScheduleData originalSchedule = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
|
||||||
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId,
|
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId,
|
||||||
@@ -660,7 +667,8 @@ public class LoanAccountData {
|
|||||||
notes, accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(), fixedEmi,
|
notes, accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(), fixedEmi,
|
||||||
product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears,
|
product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears,
|
||||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(),
|
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(),
|
||||||
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData());
|
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(),
|
||||||
|
originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||||
@@ -694,7 +702,7 @@ public class LoanAccountData {
|
|||||||
for (final ChargeData charge : product.charges()) {
|
for (final ChargeData charge : product.charges()) {
|
||||||
charges.add(charge.toLoanChargeData());
|
charges.add(charge.toLoanChargeData());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(), product.getFundId(),
|
acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(), product.getFundId(),
|
||||||
product.getFundName(), acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName,
|
product.getFundName(), acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName,
|
||||||
@@ -713,7 +721,8 @@ public class LoanAccountData {
|
|||||||
acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), acc.fixedEmiAmount,
|
acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), acc.fixedEmiAmount,
|
||||||
product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, acc.inArrears,
|
product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, acc.inArrears,
|
||||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA, product.getDaysInMonthType(),
|
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA, product.getDaysInMonthType(),
|
||||||
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData());
|
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(),
|
||||||
|
acc.originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -768,6 +777,7 @@ public class LoanAccountData {
|
|||||||
final Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
final Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
||||||
final LoanProductData product = null;
|
final LoanProductData product = null;
|
||||||
final Collection<ChargeData> overdueCharges = null;
|
final Collection<ChargeData> overdueCharges = null;
|
||||||
|
final LoanScheduleData originalSchedule = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
@@ -782,7 +792,7 @@ public class LoanAccountData {
|
|||||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
||||||
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmont, outstandingLoanBalance,
|
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmont, outstandingLoanBalance,
|
||||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData);
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -820,7 +830,7 @@ public class LoanAccountData {
|
|||||||
accountLinkingOptions, linkedAccount, disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount,
|
accountLinkingOptions, linkedAccount, disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount,
|
||||||
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData);
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
||||||
@@ -851,7 +861,8 @@ public class LoanAccountData {
|
|||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData);
|
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||||
|
acc.originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
||||||
@@ -908,7 +919,8 @@ public class LoanAccountData {
|
|||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||||
acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData);
|
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||||
|
acc.originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
||||||
@@ -931,7 +943,30 @@ public class LoanAccountData {
|
|||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, interestRecalculationData);
|
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, interestRecalculationData,
|
||||||
|
acc.originalSchedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
||||||
|
|
||||||
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
|
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
||||||
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.principal,
|
||||||
|
acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType,
|
||||||
|
acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.transactionProcessingStrategyId,
|
||||||
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
|
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
|
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
||||||
|
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
||||||
|
acc.repaymentFrequencyTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions,
|
||||||
|
acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions,
|
||||||
|
acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||||
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||||
|
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||||
|
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||||
|
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||||
|
originalSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanAccountData(
|
private LoanAccountData(
|
||||||
@@ -987,7 +1022,7 @@ public class LoanAccountData {
|
|||||||
final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing,
|
final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing,
|
||||||
final Collection<ChargeData> overdueCharges, final Boolean isNPA, final EnumOptionData daysInMonthType,
|
final Collection<ChargeData> overdueCharges, final Boolean isNPA, final EnumOptionData daysInMonthType,
|
||||||
final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||||
final LoanInterestRecalculationData interestRecalculationData) {
|
final LoanInterestRecalculationData interestRecalculationData, final LoanScheduleData originalSchedule) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountNo = accountNo;
|
this.accountNo = accountNo;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
@@ -1131,6 +1166,7 @@ public class LoanAccountData {
|
|||||||
this.daysInYearType = daysInYearType;
|
this.daysInYearType = daysInYearType;
|
||||||
this.isInterestRecalculationEnabled = isInterestRecalculationEnabled;
|
this.isInterestRecalculationEnabled = isInterestRecalculationEnabled;
|
||||||
this.interestRecalculationData = interestRecalculationData;
|
this.interestRecalculationData = interestRecalculationData;
|
||||||
|
this.originalSchedule = originalSchedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
||||||
@@ -1207,8 +1243,8 @@ public class LoanAccountData {
|
|||||||
public Long loanProductId() {
|
public Long loanProductId() {
|
||||||
return this.loanProductId;
|
return this.loanProductId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getTotalOutstandingAmount(){
|
public BigDecimal getTotalOutstandingAmount() {
|
||||||
return this.summary.getTotalOutstanding();
|
return this.summary.getTotalOutstanding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+201
-167
@@ -61,8 +61,8 @@ import org.mifosplatform.organisation.staff.domain.Staff;
|
|||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
||||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||||
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
||||||
@@ -97,7 +97,6 @@ import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
|||||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
@@ -226,7 +225,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
@Temporal(TemporalType.DATE)
|
@Temporal(TemporalType.DATE)
|
||||||
@Column(name = "rescheduledon_date")
|
@Column(name = "rescheduledon_date")
|
||||||
private Date rescheduledOnDate;
|
private Date rescheduledOnDate;
|
||||||
|
|
||||||
@ManyToOne(optional = true)
|
@ManyToOne(optional = true)
|
||||||
@JoinColumn(name = "rescheduledon_userid", nullable = true)
|
@JoinColumn(name = "rescheduledon_userid", nullable = true)
|
||||||
private AppUser rescheduledByUser;
|
private AppUser rescheduledByUser;
|
||||||
@@ -468,7 +467,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ChangedTransactionDetail addLoanCharge(final LoanCharge loanCharge, final List<Long> existingTransactionIds,
|
public ChangedTransactionDetail addLoanCharge(final LoanCharge loanCharge, final List<Long> existingTransactionIds,
|
||||||
final List<Long> existingReversedTransactionIds) {
|
final List<Long> existingReversedTransactionIds, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
|
final boolean isHolidayEnabled, final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency currency,
|
||||||
|
final LocalDate calculatedRepaymentsStartingFromDate, final CalendarInstance calendarInstanceForInterestRecalculation) {
|
||||||
ChangedTransactionDetail changedTransactionDetail = null;
|
ChangedTransactionDetail changedTransactionDetail = null;
|
||||||
|
|
||||||
validateLoanIsNotClosed(loanCharge);
|
validateLoanIsNotClosed(loanCharge);
|
||||||
@@ -528,7 +529,15 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
|
|
||||||
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||||
|
&& (loanCharge.getDueLocalDate() == null || LocalDate.now().isAfter(loanCharge.getDueLocalDate()))) {
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
|
} else {
|
||||||
|
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
|
||||||
|
}
|
||||||
if (!loanCharge.isDueAtDisbursement()) {
|
if (!loanCharge.isDueAtDisbursement()) {
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||||
@@ -825,7 +834,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||||
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||||
final Integer loanInstallmentNumber) {
|
final Integer loanInstallmentNumber, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
|
final boolean isHolidayEnabled, final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency currency,
|
||||||
|
final LocalDate calculatedRepaymentsStartingFromDate, final CalendarInstance calendarInstanceForInterestRecalculation) {
|
||||||
|
|
||||||
validateLoanIsNotClosed(loanCharge);
|
validateLoanIsNotClosed(loanCharge);
|
||||||
|
|
||||||
@@ -854,6 +865,12 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
transactionDate, feeChargesWaived, penaltyChargesWaived);
|
transactionDate, feeChargesWaived, penaltyChargesWaived);
|
||||||
this.loanTransactions.add(waiveLoanChargeTransaction);
|
this.loanTransactions.add(waiveLoanChargeTransaction);
|
||||||
|
|
||||||
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||||
|
&& (loanCharge.getDueLocalDate() == null || LocalDate.now().isAfter(loanCharge.getDueLocalDate()))) {
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
|
}
|
||||||
// Waive of charges whose due date falls after latest 'repayment'
|
// Waive of charges whose due date falls after latest 'repayment'
|
||||||
// transaction dont require entire loan schedule to be reprocessed.
|
// transaction dont require entire loan schedule to be reprocessed.
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
@@ -1811,17 +1828,19 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
this.loanTermVariations.add(loanVariationTerms);
|
this.loanTermVariations.add(loanVariationTerms);
|
||||||
isEmiAmountChanged = true;
|
isEmiAmountChanged = true;
|
||||||
}
|
}
|
||||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) {
|
|
||||||
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
|
||||||
workingDays);
|
|
||||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
|
||||||
}
|
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||||
&& (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) {
|
&& (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) {
|
||||||
LocalDate recalculateFrom = null;
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
|
} else if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule
|
||||||
|
|| isEmiAmountChanged) {
|
||||||
|
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||||
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
|
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
handleDisbursementTransaction(actualDisbursementDate);
|
handleDisbursementTransaction(actualDisbursementDate);
|
||||||
@@ -2028,6 +2047,19 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
||||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
|
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
|
||||||
|
|
||||||
|
final LoanScheduleModel loanSchedule = regenerateScheduleModel(loanScheduleFactory, applicationCurrency,
|
||||||
|
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays);
|
||||||
|
|
||||||
|
updateLoanSchedule(loanSchedule);
|
||||||
|
Set<LoanCharge> charges = this.charges();
|
||||||
|
for (LoanCharge loanCharge : charges) {
|
||||||
|
recalculateLoanCharge(loanCharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanScheduleModel regenerateScheduleModel(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||||
|
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
||||||
|
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
|
||||||
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
|
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
|
||||||
final LoanScheduleGenerator loanScheduleGenerator = loanScheduleFactory.create(interestMethod);
|
final LoanScheduleGenerator loanScheduleGenerator = loanScheduleFactory.create(interestMethod);
|
||||||
|
|
||||||
@@ -2064,12 +2096,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, charges(),
|
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, charges(),
|
||||||
isHolidayEnabled, holidays, workingDays);
|
isHolidayEnabled, holidays, workingDays);
|
||||||
|
return loanSchedule;
|
||||||
updateLoanSchedule(loanSchedule);
|
|
||||||
Set<LoanCharge> charges = this.charges();
|
|
||||||
for (LoanCharge loanCharge : charges) {
|
|
||||||
recalculateLoanCharge(loanCharge);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDisbursementTransaction(final LocalDate disbursedOn) {
|
private void handleDisbursementTransaction(final LocalDate disbursedOn) {
|
||||||
@@ -4003,13 +4030,14 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
command.stringValueOfParameterNamed(LoanApiConstants.disbursementIdParameterName));
|
command.stringValueOfParameterNamed(LoanApiConstants.disbursementIdParameterName));
|
||||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
|
||||||
workingDays);
|
|
||||||
|
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
LocalDate recalculateFrom = null;
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
|
} else {
|
||||||
|
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
@@ -4310,173 +4338,179 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return this.isNpa;
|
return this.isNpa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return List of loan repayments schedule objects
|
* @return List of loan repayments schedule objects
|
||||||
**/
|
**/
|
||||||
public List<LoanRepaymentScheduleInstallment> getRepaymentScheduleInstallments() {
|
public List<LoanRepaymentScheduleInstallment> getRepaymentScheduleInstallments() {
|
||||||
return this.repaymentScheduleInstallments;
|
return this.repaymentScheduleInstallments;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Loan product minimum repayments schedule related detail
|
* @return Loan product minimum repayments schedule related detail
|
||||||
**/
|
**/
|
||||||
public LoanProductRelatedDetail getLoanRepaymentScheduleDetail() {
|
public LoanProductRelatedDetail getLoanRepaymentScheduleDetail() {
|
||||||
return this.loanRepaymentScheduleDetail;
|
return this.loanRepaymentScheduleDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Loan Fixed Emi amount
|
* @return Loan Fixed Emi amount
|
||||||
**/
|
**/
|
||||||
public BigDecimal getFixedEmiAmount() {
|
public BigDecimal getFixedEmiAmount() {
|
||||||
return this.fixedEmiAmount;
|
return this.fixedEmiAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return maximum outstanding loan balance
|
* @return maximum outstanding loan balance
|
||||||
**/
|
**/
|
||||||
public BigDecimal getMaxOutstandingLoanBalance() {
|
public BigDecimal getMaxOutstandingLoanBalance() {
|
||||||
return this.maxOutstandingLoanBalance;
|
return this.maxOutstandingLoanBalance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dueDate the due date of the installment
|
* @param dueDate
|
||||||
* @return a schedule installment with similar due date to the one provided
|
* the due date of the installment
|
||||||
|
* @return a schedule installment with similar due date to the one provided
|
||||||
**/
|
**/
|
||||||
public LoanRepaymentScheduleInstallment getRepaymentScheduleInstallment(LocalDate dueDate) {
|
public LoanRepaymentScheduleInstallment getRepaymentScheduleInstallment(LocalDate dueDate) {
|
||||||
LoanRepaymentScheduleInstallment installment = null;
|
LoanRepaymentScheduleInstallment installment = null;
|
||||||
|
|
||||||
if(dueDate != null) {
|
if (dueDate != null) {
|
||||||
for(LoanRepaymentScheduleInstallment repaymentScheduleInstallment : this.repaymentScheduleInstallments) {
|
for (LoanRepaymentScheduleInstallment repaymentScheduleInstallment : this.repaymentScheduleInstallments) {
|
||||||
|
|
||||||
if(repaymentScheduleInstallment.getDueDate().isEqual(dueDate)) {
|
if (repaymentScheduleInstallment.getDueDate().isEqual(dueDate)) {
|
||||||
installment = repaymentScheduleInstallment;
|
installment = repaymentScheduleInstallment;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return installment;
|
return installment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param loan the Loan object
|
* @param loan
|
||||||
* @return loan disbursement data
|
* the Loan object
|
||||||
**/
|
* @return loan disbursement data
|
||||||
public List<DisbursementData> getDisbursmentData() {
|
**/
|
||||||
Iterator<LoanDisbursementDetails> iterator = this.getDisbursementDetails().iterator();
|
public List<DisbursementData> getDisbursmentData() {
|
||||||
List<DisbursementData> disbursementData = new ArrayList<DisbursementData>();
|
Iterator<LoanDisbursementDetails> iterator = this.getDisbursementDetails().iterator();
|
||||||
|
List<DisbursementData> disbursementData = new ArrayList<DisbursementData>();
|
||||||
while(iterator.hasNext()) {
|
|
||||||
LoanDisbursementDetails loanDisbursementDetails = iterator.next();
|
while (iterator.hasNext()) {
|
||||||
|
LoanDisbursementDetails loanDisbursementDetails = iterator.next();
|
||||||
LocalDate expectedDisbursementDate = null;
|
|
||||||
LocalDate actualDisbursementDate = null;
|
LocalDate expectedDisbursementDate = null;
|
||||||
|
LocalDate actualDisbursementDate = null;
|
||||||
if(loanDisbursementDetails.expectedDisbursementDate() != null) {
|
|
||||||
expectedDisbursementDate = new LocalDate(loanDisbursementDetails.expectedDisbursementDate());
|
if (loanDisbursementDetails.expectedDisbursementDate() != null) {
|
||||||
}
|
expectedDisbursementDate = new LocalDate(loanDisbursementDetails.expectedDisbursementDate());
|
||||||
|
}
|
||||||
if(loanDisbursementDetails.actualDisbursementDate() != null) {
|
|
||||||
actualDisbursementDate = new LocalDate(loanDisbursementDetails.actualDisbursementDate());
|
if (loanDisbursementDetails.actualDisbursementDate() != null) {
|
||||||
}
|
actualDisbursementDate = new LocalDate(loanDisbursementDetails.actualDisbursementDate());
|
||||||
|
}
|
||||||
disbursementData.add(new DisbursementData(loanDisbursementDetails.getId(), expectedDisbursementDate,
|
|
||||||
actualDisbursementDate, loanDisbursementDetails.principal(), loanDisbursementDetails.approvedPrincipal()));
|
disbursementData.add(new DisbursementData(loanDisbursementDetails.getId(), expectedDisbursementDate, actualDisbursementDate,
|
||||||
}
|
loanDisbursementDetails.principal(), loanDisbursementDetails.approvedPrincipal()));
|
||||||
|
}
|
||||||
return disbursementData;
|
|
||||||
}
|
return disbursementData;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* @param loan the Loan object
|
/**
|
||||||
* @return application terms of the Loan object
|
* @param loan
|
||||||
**/
|
* the Loan object
|
||||||
@SuppressWarnings({ "unused" })
|
* @return application terms of the Loan object
|
||||||
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency) {
|
**/
|
||||||
LoanProduct loanProduct = loanProduct();
|
@SuppressWarnings({ "unused" })
|
||||||
//LoanProductRelatedDetail loanProductRelatedDetail = getLoanRepaymentScheduleDetail();
|
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency) {
|
||||||
final MonetaryCurrency currency = this.loanRepaymentScheduleDetail.getCurrency();
|
LoanProduct loanProduct = loanProduct();
|
||||||
|
// LoanProductRelatedDetail loanProductRelatedDetail =
|
||||||
final Integer loanTermFrequency = getTermFrequency();
|
// getLoanRepaymentScheduleDetail();
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
final MonetaryCurrency currency = this.loanRepaymentScheduleDetail.getCurrency();
|
||||||
|
|
||||||
final Integer numberOfRepayments = this.loanRepaymentScheduleDetail.getNumberOfRepayments();
|
final Integer loanTermFrequency = getTermFrequency();
|
||||||
final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery();
|
final PeriodFrequencyType loanTermPeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType();
|
|
||||||
|
final Integer numberOfRepayments = this.loanRepaymentScheduleDetail.getNumberOfRepayments();
|
||||||
final AmortizationMethod amortizationMethod = this.loanRepaymentScheduleDetail.getAmortizationMethod();
|
final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery();
|
||||||
|
final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType();
|
||||||
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
|
|
||||||
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = this.loanRepaymentScheduleDetail.getInterestCalculationPeriodMethod();
|
final AmortizationMethod amortizationMethod = this.loanRepaymentScheduleDetail.getAmortizationMethod();
|
||||||
|
|
||||||
final BigDecimal interestRatePerPeriod = this.loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod();
|
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
|
||||||
final PeriodFrequencyType interestRatePeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = this.loanRepaymentScheduleDetail
|
||||||
|
.getInterestCalculationPeriodMethod();
|
||||||
final BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
|
||||||
final Money principalMoney = this.loanRepaymentScheduleDetail.getPrincipal();
|
final BigDecimal interestRatePerPeriod = this.loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod();
|
||||||
|
final PeriodFrequencyType interestRatePeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
||||||
final LocalDate expectedDisbursementDate = getExpectedDisbursedOnLocalDate();
|
|
||||||
final LocalDate repaymentsStartingFromDate = getExpectedFirstRepaymentOnDate();
|
final BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
|
final Money principalMoney = this.loanRepaymentScheduleDetail.getPrincipal();
|
||||||
|
|
||||||
// TODO get calender linked to loan if any exist. As of 17-07-2014, could not find a link in the database.
|
final LocalDate expectedDisbursementDate = getExpectedDisbursedOnLocalDate();
|
||||||
// skip for now and set the Calender object to null
|
final LocalDate repaymentsStartingFromDate = getExpectedFirstRepaymentOnDate();
|
||||||
Calendar calendar = null;
|
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
|
||||||
|
|
||||||
final Integer graceOnPrincipalPayment = this.loanRepaymentScheduleDetail.graceOnPrincipalPayment();
|
// TODO get calender linked to loan if any exist. As of 17-07-2014,
|
||||||
final Integer graceOnInterestPayment = this.loanRepaymentScheduleDetail.graceOnInterestPayment();
|
// could not find a link in the database.
|
||||||
final Integer graceOnInterestCharged = this.loanRepaymentScheduleDetail.graceOnInterestCharged();
|
// skip for now and set the Calender object to null
|
||||||
final LocalDate interestChargedFromDate = getInterestChargedFromDate();
|
Calendar calendar = null;
|
||||||
final Integer graceOnArrearsAgeing = this.loanRepaymentScheduleDetail.getGraceOnDueDate();
|
|
||||||
|
final Integer graceOnPrincipalPayment = this.loanRepaymentScheduleDetail.graceOnPrincipalPayment();
|
||||||
final Money inArrearsToleranceMoney = this.loanRepaymentScheduleDetail.getInArrearsTolerance();
|
final Integer graceOnInterestPayment = this.loanRepaymentScheduleDetail.graceOnInterestPayment();
|
||||||
final BigDecimal emiAmount = getFixedEmiAmount();
|
final Integer graceOnInterestCharged = this.loanRepaymentScheduleDetail.graceOnInterestCharged();
|
||||||
final BigDecimal maxOutstandingBalance = getMaxOutstandingLoanBalance();
|
final LocalDate interestChargedFromDate = getInterestChargedFromDate();
|
||||||
|
final Integer graceOnArrearsAgeing = this.loanRepaymentScheduleDetail.getGraceOnDueDate();
|
||||||
final List<DisbursementData> disbursementData = getDisbursmentData();
|
|
||||||
|
final Money inArrearsToleranceMoney = this.loanRepaymentScheduleDetail.getInArrearsTolerance();
|
||||||
final List<LoanTermVariationsData> loanVariationTermsData = new ArrayList<LoanTermVariationsData>();
|
final BigDecimal emiAmount = getFixedEmiAmount();
|
||||||
|
final BigDecimal maxOutstandingBalance = getMaxOutstandingLoanBalance();
|
||||||
|
|
||||||
|
final List<DisbursementData> disbursementData = getDisbursmentData();
|
||||||
|
|
||||||
|
final List<LoanTermVariationsData> loanVariationTermsData = new ArrayList<LoanTermVariationsData>();
|
||||||
LoanTermVariationsData data = new LoanTermVariationsData(null,
|
LoanTermVariationsData data = new LoanTermVariationsData(null,
|
||||||
LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount);
|
LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount);
|
||||||
loanVariationTermsData.add(data);
|
loanVariationTermsData.add(data);
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType,
|
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType,
|
||||||
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, inArrearsToleranceMoney,
|
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, inArrearsToleranceMoney,
|
||||||
this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData, maxOutstandingBalance,
|
this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData, maxOutstandingBalance,
|
||||||
loanVariationTermsData, interestChargedFromDate);
|
loanVariationTermsData, interestChargedFromDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Loan summary embedded object
|
* @return Loan summary embedded object
|
||||||
**/
|
**/
|
||||||
public LoanSummary getLoanSummary() {
|
public LoanSummary getLoanSummary() {
|
||||||
return this.summary;
|
return this.summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateRescheduledByUser(AppUser rescheduledByUser) {
|
public void updateRescheduledByUser(AppUser rescheduledByUser) {
|
||||||
this.rescheduledByUser = rescheduledByUser;
|
this.rescheduledByUser = rescheduledByUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanProductRelatedDetail getLoanProductRelatedDetail() {
|
public LoanProductRelatedDetail getLoanProductRelatedDetail() {
|
||||||
return this.loanRepaymentScheduleDetail;
|
return this.loanRepaymentScheduleDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateNumberOfRepayments(Integer numberOfRepayments) {
|
public void updateNumberOfRepayments(Integer numberOfRepayments) {
|
||||||
this.loanRepaymentScheduleDetail.updateNumberOfRepayments(numberOfRepayments);
|
this.loanRepaymentScheduleDetail.updateNumberOfRepayments(numberOfRepayments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateRescheduledOnDate(LocalDate rescheduledOnDate) {
|
||||||
|
|
||||||
|
if (rescheduledOnDate != null) {
|
||||||
|
this.rescheduledOnDate = rescheduledOnDate.toDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTermFrequency(Integer termFrequency) {
|
||||||
|
|
||||||
|
if (termFrequency != null) {
|
||||||
|
this.termFrequency = termFrequency;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateRescheduledOnDate(LocalDate rescheduledOnDate) {
|
|
||||||
|
|
||||||
if(rescheduledOnDate != null) {
|
|
||||||
this.rescheduledOnDate = rescheduledOnDate.toDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateTermFrequency(Integer termFrequency) {
|
|
||||||
|
|
||||||
if(termFrequency != null) {
|
|
||||||
this.termFrequency = termFrequency;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+21
@@ -75,6 +75,27 @@ public class LoanScheduleData {
|
|||||||
this.totalOutstanding = totalOutstanding;
|
this.totalOutstanding = totalOutstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanScheduleData(final CurrencyData currency, final Collection<LoanSchedulePeriodData> periods, final Integer loanTermInDays,
|
||||||
|
final BigDecimal totalPrincipalDisbursed, final BigDecimal totalPrincipalExpected, final BigDecimal totalInterestCharged,
|
||||||
|
final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected) {
|
||||||
|
this.currency = currency;
|
||||||
|
this.periods = periods;
|
||||||
|
this.loanTermInDays = loanTermInDays;
|
||||||
|
this.totalPrincipalDisbursed = totalPrincipalDisbursed;
|
||||||
|
this.totalPrincipalExpected = totalPrincipalExpected;
|
||||||
|
this.totalPrincipalPaid = null;
|
||||||
|
this.totalInterestCharged = totalInterestCharged;
|
||||||
|
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
||||||
|
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
||||||
|
this.totalWaived = null;
|
||||||
|
this.totalWrittenOff = null;
|
||||||
|
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||||
|
this.totalRepayment = null;
|
||||||
|
this.totalPaidInAdvance = null;
|
||||||
|
this.totalPaidLate = null;
|
||||||
|
this.totalOutstanding = null;
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<LoanSchedulePeriodData> getPeriods() {
|
public Collection<LoanSchedulePeriodData> getPeriods() {
|
||||||
return this.periods;
|
return this.periods;
|
||||||
}
|
}
|
||||||
|
|||||||
+288
-351
@@ -9,9 +9,8 @@ import java.math.BigDecimal;
|
|||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -30,18 +29,16 @@ import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
|||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummary;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummary;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementDisbursementDateException;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementDisbursementDateException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementEmiAmountException;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementEmiAmountException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRepaymentScheduleHistory;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -522,354 +519,294 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
|
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
|
||||||
totalOutstanding);
|
totalOutstanding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||||
final ApplicationCurrency applicationCurrency, final boolean isHolidayEnabled,
|
final ApplicationCurrency applicationCurrency, final boolean isHolidayEnabled, final List<Holiday> holidays,
|
||||||
final List<Holiday> holidays, final WorkingDays workingDays) {
|
final WorkingDays workingDays) {
|
||||||
|
|
||||||
final Loan loan = loanRescheduleRequest.getLoan();
|
final Loan loan = loanRescheduleRequest.getLoan();
|
||||||
final LoanSummary loanSummary = loan.getSummary();
|
final LoanSummary loanSummary = loan.getSummary();
|
||||||
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
||||||
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
||||||
|
|
||||||
// create an archive of the current loan schedule installments
|
// create an archive of the current loan schedule installments
|
||||||
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = createLoanScheduleArchive(loanRescheduleRequest);
|
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = null;
|
||||||
|
|
||||||
// get the initial list of repayment installments
|
// get the initial list of repayment installments
|
||||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||||
|
|
||||||
// sort list by installment number in ASC order
|
// sort list by installment number in ASC order
|
||||||
Collections.sort(repaymentScheduleInstallments, LoanRepaymentScheduleInstallment.installmentNumberComparator);
|
Collections.sort(repaymentScheduleInstallments, LoanRepaymentScheduleInstallment.installmentNumberComparator);
|
||||||
|
|
||||||
final Collection<LoanRescheduleModelRepaymentPeriod> periods = new ArrayList<LoanRescheduleModelRepaymentPeriod>();
|
final Collection<LoanRescheduleModelRepaymentPeriod> periods = new ArrayList<>();
|
||||||
|
|
||||||
Money outstandingLoanBalance = loan.getPrincpal();
|
Money outstandingLoanBalance = loan.getPrincpal();
|
||||||
|
|
||||||
for(LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
|
for (LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
|
||||||
|
|
||||||
Integer oldPeriodNumber = repaymentScheduleInstallment.getInstallmentNumber();
|
Integer oldPeriodNumber = repaymentScheduleInstallment.getInstallmentNumber();
|
||||||
LocalDate fromDate = repaymentScheduleInstallment.getFromDate();
|
LocalDate fromDate = repaymentScheduleInstallment.getFromDate();
|
||||||
LocalDate dueDate = repaymentScheduleInstallment.getDueDate();
|
LocalDate dueDate = repaymentScheduleInstallment.getDueDate();
|
||||||
Money principalDue = repaymentScheduleInstallment.getPrincipal(currency);
|
Money principalDue = repaymentScheduleInstallment.getPrincipal(currency);
|
||||||
Money interestDue = repaymentScheduleInstallment.getInterestCharged(currency);
|
Money interestDue = repaymentScheduleInstallment.getInterestCharged(currency);
|
||||||
Money feeChargesDue = repaymentScheduleInstallment.getFeeChargesCharged(currency);
|
Money feeChargesDue = repaymentScheduleInstallment.getFeeChargesCharged(currency);
|
||||||
Money penaltyChargesDue = repaymentScheduleInstallment.getPenaltyChargesCharged(currency);
|
Money penaltyChargesDue = repaymentScheduleInstallment.getPenaltyChargesCharged(currency);
|
||||||
Money totalDue = principalDue.plus(interestDue).plus(feeChargesDue).plus(penaltyChargesDue);
|
Money totalDue = principalDue.plus(interestDue).plus(feeChargesDue).plus(penaltyChargesDue);
|
||||||
|
|
||||||
outstandingLoanBalance = outstandingLoanBalance.minus(principalDue);
|
outstandingLoanBalance = outstandingLoanBalance.minus(principalDue);
|
||||||
|
|
||||||
LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod.instance(oldPeriodNumber, oldPeriodNumber,
|
LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod
|
||||||
fromDate, dueDate, principalDue, outstandingLoanBalance, interestDue, feeChargesDue, penaltyChargesDue,
|
.instance(oldPeriodNumber, oldPeriodNumber, fromDate, dueDate, principalDue, outstandingLoanBalance, interestDue,
|
||||||
totalDue, false);
|
feeChargesDue, penaltyChargesDue, totalDue, false);
|
||||||
|
|
||||||
periods.add(period);
|
periods.add(period);
|
||||||
}
|
}
|
||||||
|
|
||||||
Money outstandingBalance = loan.getPrincpal();
|
Money outstandingBalance = loan.getPrincpal();
|
||||||
Money totalCumulativePrincipal = Money.zero(currency);
|
Money totalCumulativePrincipal = Money.zero(currency);
|
||||||
Money totalCumulativeInterest = Money.zero(currency);
|
Money totalCumulativeInterest = Money.zero(currency);
|
||||||
Money actualTotalCumulativeInterest = Money.zero(currency);
|
Money actualTotalCumulativeInterest = Money.zero(currency);
|
||||||
Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
|
Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
|
||||||
Money totalPrincipalBeforeReschedulePeriod = Money.zero(currency);
|
Money totalPrincipalBeforeReschedulePeriod = Money.zero(currency);
|
||||||
|
|
||||||
LocalDate installmentDueDate = null;
|
LocalDate installmentDueDate = null;
|
||||||
LocalDate adjustedInstallmentDueDate = null;
|
LocalDate adjustedInstallmentDueDate = null;
|
||||||
LocalDate installmentFromDate = null;
|
LocalDate installmentFromDate = null;
|
||||||
Integer rescheduleFromInstallmentNo = defaultToZeroIfNull(loanRescheduleRequest.getRescheduleFromInstallment());
|
Integer rescheduleFromInstallmentNo = defaultToZeroIfNull(loanRescheduleRequest.getRescheduleFromInstallment());
|
||||||
Integer installmentNumber = rescheduleFromInstallmentNo;
|
Integer installmentNumber = rescheduleFromInstallmentNo;
|
||||||
Integer graceOnPrincipal = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnPrincipal());
|
Integer graceOnPrincipal = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnPrincipal());
|
||||||
Integer graceOnInterest = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnInterest());
|
Integer graceOnInterest = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnInterest());
|
||||||
Integer extraTerms = defaultToZeroIfNull(loanRescheduleRequest.getExtraTerms());
|
Integer extraTerms = defaultToZeroIfNull(loanRescheduleRequest.getExtraTerms());
|
||||||
final boolean recalculateInterest = loanRescheduleRequest.getRecalculateInterest();
|
final boolean recalculateInterest = loanRescheduleRequest.getRecalculateInterest();
|
||||||
Integer numberOfRepayments = repaymentScheduleInstallments.size();
|
Integer numberOfRepayments = repaymentScheduleInstallments.size();
|
||||||
Integer rescheduleNumberOfRepayments = numberOfRepayments;
|
Integer rescheduleNumberOfRepayments = numberOfRepayments;
|
||||||
final Money principal = loan.getPrincpal();
|
final Money principal = loan.getPrincpal();
|
||||||
final Money totalPrincipalOutstanding = Money.of(currency, loanSummary.getTotalPrincipalOutstanding());
|
final Money totalPrincipalOutstanding = Money.of(currency, loanSummary.getTotalPrincipalOutstanding());
|
||||||
LocalDate adjustedDueDate = loanRescheduleRequest.getAdjustedDueDate();
|
LocalDate adjustedDueDate = loanRescheduleRequest.getAdjustedDueDate();
|
||||||
BigDecimal newInterestRate = loanRescheduleRequest.getInterestRate();
|
BigDecimal newInterestRate = loanRescheduleRequest.getInterestRate();
|
||||||
int loanTermInDays = Integer.valueOf(0);
|
int loanTermInDays = Integer.valueOf(0);
|
||||||
|
|
||||||
if(rescheduleFromInstallmentNo > 0) {
|
if (rescheduleFromInstallmentNo > 0) {
|
||||||
// this will hold the loan repayment installment that is before the reschedule start installment
|
// this will hold the loan repayment installment that is before the
|
||||||
// (rescheduleFrominstallment)
|
// reschedule start installment
|
||||||
LoanRepaymentScheduleInstallment previousInstallment = null;
|
// (rescheduleFrominstallment)
|
||||||
|
LoanRepaymentScheduleInstallment previousInstallment = null;
|
||||||
// get the install number of the previous installment
|
|
||||||
int previousInstallmentNo = rescheduleFromInstallmentNo - 1;
|
// get the install number of the previous installment
|
||||||
|
int previousInstallmentNo = rescheduleFromInstallmentNo - 1;
|
||||||
// only fetch the installment if the number is greater than 0
|
|
||||||
if(previousInstallmentNo > 0) {
|
// only fetch the installment if the number is greater than 0
|
||||||
previousInstallment = loan.fetchRepaymentScheduleInstallment(previousInstallmentNo);
|
if (previousInstallmentNo > 0) {
|
||||||
}
|
previousInstallment = loan.fetchRepaymentScheduleInstallment(previousInstallmentNo);
|
||||||
|
}
|
||||||
LoanRepaymentScheduleInstallment firstInstallment = loan.fetchRepaymentScheduleInstallment(1);
|
|
||||||
|
LoanRepaymentScheduleInstallment firstInstallment = loan.fetchRepaymentScheduleInstallment(1);
|
||||||
// the "installment from date" is equal to the due date of the previous installment, if it exists
|
|
||||||
if(previousInstallment != null) {
|
// the "installment from date" is equal to the due date of the
|
||||||
installmentFromDate = previousInstallment.getDueDate();
|
// previous installment, if it exists
|
||||||
}
|
if (previousInstallment != null) {
|
||||||
|
installmentFromDate = previousInstallment.getDueDate();
|
||||||
else {
|
}
|
||||||
installmentFromDate = firstInstallment.getFromDate();
|
|
||||||
}
|
else {
|
||||||
|
installmentFromDate = firstInstallment.getFromDate();
|
||||||
installmentDueDate = installmentFromDate;
|
}
|
||||||
LocalDate periodStartDateApplicableForInterest = installmentFromDate;
|
|
||||||
Integer periodNumber = 1;
|
installmentDueDate = installmentFromDate;
|
||||||
outstandingLoanBalance = loan.getPrincpal();
|
LocalDate periodStartDateApplicableForInterest = installmentFromDate;
|
||||||
|
Integer periodNumber = 1;
|
||||||
for(LoanRescheduleModelRepaymentPeriod period : periods) {
|
outstandingLoanBalance = loan.getPrincpal();
|
||||||
|
|
||||||
if(period.periodDueDate().isBefore(loanRescheduleRequest.getRescheduleFromDate())) {
|
for (LoanRescheduleModelRepaymentPeriod period : periods) {
|
||||||
|
|
||||||
totalPrincipalBeforeReschedulePeriod = totalPrincipalBeforeReschedulePeriod.plus(period.principalDue());
|
if (period.periodDueDate().isBefore(loanRescheduleRequest.getRescheduleFromDate())) {
|
||||||
actualTotalCumulativeInterest = actualTotalCumulativeInterest.plus(period.interestDue());
|
|
||||||
rescheduleNumberOfRepayments--;
|
totalPrincipalBeforeReschedulePeriod = totalPrincipalBeforeReschedulePeriod.plus(period.principalDue());
|
||||||
outstandingLoanBalance = outstandingLoanBalance.minus(period.principalDue());
|
actualTotalCumulativeInterest = actualTotalCumulativeInterest.plus(period.interestDue());
|
||||||
outstandingBalance = outstandingBalance.minus(period.principalDue());
|
rescheduleNumberOfRepayments--;
|
||||||
}
|
outstandingLoanBalance = outstandingLoanBalance.minus(period.principalDue());
|
||||||
}
|
outstandingBalance = outstandingBalance.minus(period.principalDue());
|
||||||
|
}
|
||||||
while(graceOnPrincipal > 0 || graceOnInterest > 0) {
|
}
|
||||||
|
|
||||||
LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod.instance(0, 0, new LocalDate(),
|
while (graceOnPrincipal > 0 || graceOnInterest > 0) {
|
||||||
new LocalDate(), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency),
|
|
||||||
Money.zero(currency), Money.zero(currency), true);
|
LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod.instance(0, 0, new LocalDate(),
|
||||||
|
new LocalDate(), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency),
|
||||||
periods.add(period);
|
Money.zero(currency), Money.zero(currency), true);
|
||||||
|
|
||||||
if(graceOnPrincipal > 0) {
|
periods.add(period);
|
||||||
graceOnPrincipal--;
|
|
||||||
}
|
if (graceOnPrincipal > 0) {
|
||||||
|
graceOnPrincipal--;
|
||||||
if(graceOnInterest > 0) {
|
}
|
||||||
graceOnInterest--;
|
|
||||||
}
|
if (graceOnInterest > 0) {
|
||||||
|
graceOnInterest--;
|
||||||
rescheduleNumberOfRepayments++;
|
}
|
||||||
numberOfRepayments++;
|
|
||||||
}
|
rescheduleNumberOfRepayments++;
|
||||||
|
numberOfRepayments++;
|
||||||
while(extraTerms > 0) {
|
}
|
||||||
|
|
||||||
LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod.instance(0, 0, new LocalDate(),
|
while (extraTerms > 0) {
|
||||||
new LocalDate(), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency),
|
|
||||||
Money.zero(currency), Money.zero(currency), true);
|
LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod.instance(0, 0, new LocalDate(),
|
||||||
|
new LocalDate(), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency),
|
||||||
periods.add(period);
|
Money.zero(currency), Money.zero(currency), true);
|
||||||
|
|
||||||
extraTerms--;
|
periods.add(period);
|
||||||
rescheduleNumberOfRepayments++;
|
|
||||||
numberOfRepayments++;
|
extraTerms--;
|
||||||
}
|
rescheduleNumberOfRepayments++;
|
||||||
|
numberOfRepayments++;
|
||||||
// get the loan application terms from the Loan object
|
}
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency);
|
|
||||||
|
// get the loan application terms from the Loan object
|
||||||
// update the number of repayments
|
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency);
|
||||||
loanApplicationTerms.updateNumberOfRepayments(numberOfRepayments);
|
|
||||||
|
// update the number of repayments
|
||||||
LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, isHolidayEnabled,
|
loanApplicationTerms.updateNumberOfRepayments(numberOfRepayments);
|
||||||
holidays, workingDays);
|
|
||||||
loanApplicationTerms.updateLoanEndDate(loanEndDate);
|
LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
if(newInterestRate != null) {
|
loanApplicationTerms.updateLoanEndDate(loanEndDate);
|
||||||
loanApplicationTerms.updateAnnualNominalInterestRate(newInterestRate);
|
|
||||||
loanApplicationTerms.updateInterestRatePerPeriod(newInterestRate);
|
if (newInterestRate != null) {
|
||||||
}
|
loanApplicationTerms.updateAnnualNominalInterestRate(newInterestRate);
|
||||||
|
loanApplicationTerms.updateInterestRatePerPeriod(newInterestRate);
|
||||||
graceOnPrincipal = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnPrincipal());
|
}
|
||||||
graceOnInterest = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnInterest());
|
|
||||||
|
graceOnPrincipal = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnPrincipal());
|
||||||
loanApplicationTerms.updateInterestPaymentGrace(graceOnInterest);
|
graceOnInterest = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnInterest());
|
||||||
loanApplicationTerms.updatePrincipalGrace(graceOnPrincipal);
|
|
||||||
|
loanApplicationTerms.updateInterestPaymentGrace(graceOnInterest);
|
||||||
loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
|
loanApplicationTerms.updatePrincipalGrace(graceOnPrincipal);
|
||||||
|
|
||||||
|
loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
|
||||||
loanApplicationTerms.updateNumberOfRepayments(rescheduleNumberOfRepayments);
|
loanApplicationTerms.updateNumberOfRepayments(rescheduleNumberOfRepayments);
|
||||||
loanApplicationTerms.updateLoanTermFrequency(rescheduleNumberOfRepayments);
|
loanApplicationTerms.updateLoanTermFrequency(rescheduleNumberOfRepayments);
|
||||||
loanApplicationTerms.updateInterestChargedFromDate(periodStartDateApplicableForInterest);
|
loanApplicationTerms.updateInterestChargedFromDate(periodStartDateApplicableForInterest);
|
||||||
|
|
||||||
Money totalInterestChargedForFullLoanTerm = loanApplicationTerms.calculateTotalInterestCharged(
|
Money totalInterestChargedForFullLoanTerm = loanApplicationTerms.calculateTotalInterestCharged(
|
||||||
this.paymentPeriodsInOneYearCalculator, mathContext);
|
this.paymentPeriodsInOneYearCalculator, mathContext);
|
||||||
|
|
||||||
if(!recalculateInterest && newInterestRate == null) {
|
if (!recalculateInterest && newInterestRate == null) {
|
||||||
totalInterestChargedForFullLoanTerm = Money.of(currency, loanSummary.getTotalInterestCharged());
|
totalInterestChargedForFullLoanTerm = Money.of(currency, loanSummary.getTotalInterestCharged());
|
||||||
totalInterestChargedForFullLoanTerm = totalInterestChargedForFullLoanTerm.minus(actualTotalCumulativeInterest);
|
totalInterestChargedForFullLoanTerm = totalInterestChargedForFullLoanTerm.minus(actualTotalCumulativeInterest);
|
||||||
|
|
||||||
loanApplicationTerms.updateTotalInterestDue(totalInterestChargedForFullLoanTerm);
|
loanApplicationTerms.updateTotalInterestDue(totalInterestChargedForFullLoanTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(LoanRescheduleModelRepaymentPeriod period : periods) {
|
for (LoanRescheduleModelRepaymentPeriod period : periods) {
|
||||||
|
|
||||||
if(period.periodDueDate().isEqual(loanRescheduleRequest.getRescheduleFromDate()) ||
|
if (period.periodDueDate().isEqual(loanRescheduleRequest.getRescheduleFromDate())
|
||||||
period.periodDueDate().isAfter(loanRescheduleRequest.getRescheduleFromDate()) ||
|
|| period.periodDueDate().isAfter(loanRescheduleRequest.getRescheduleFromDate()) || period.isNew()) {
|
||||||
period.isNew()) {
|
|
||||||
|
installmentDueDate = this.scheduledDateGenerator.generateNextRepaymentDate(installmentDueDate, loanApplicationTerms,
|
||||||
installmentDueDate = this.scheduledDateGenerator.generateNextRepaymentDate(installmentDueDate, loanApplicationTerms,
|
false);
|
||||||
false);
|
|
||||||
|
if (adjustedDueDate != null && periodNumber == 1) {
|
||||||
if(adjustedDueDate != null && periodNumber == 1) {
|
installmentDueDate = adjustedDueDate;
|
||||||
installmentDueDate = adjustedDueDate;
|
}
|
||||||
}
|
|
||||||
|
adjustedInstallmentDueDate = this.scheduledDateGenerator.adjustRepaymentDate(installmentDueDate, loanApplicationTerms,
|
||||||
adjustedInstallmentDueDate = this.scheduledDateGenerator.adjustRepaymentDate(installmentDueDate, loanApplicationTerms,
|
isHolidayEnabled, holidays, workingDays);
|
||||||
isHolidayEnabled, holidays, workingDays);
|
|
||||||
|
final int daysInInstallment = Days.daysBetween(installmentFromDate, adjustedInstallmentDueDate).getDays();
|
||||||
final int daysInInstallment = Days.daysBetween(installmentFromDate, adjustedInstallmentDueDate).getDays();
|
|
||||||
|
period.updatePeriodNumber(installmentNumber);
|
||||||
period.updatePeriodNumber(installmentNumber);
|
period.updatePeriodFromDate(installmentFromDate);
|
||||||
period.updatePeriodFromDate(installmentFromDate);
|
period.updatePeriodDueDate(adjustedInstallmentDueDate);
|
||||||
period.updatePeriodDueDate(adjustedInstallmentDueDate);
|
|
||||||
|
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
|
||||||
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
|
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest,
|
||||||
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, adjustedInstallmentDueDate,
|
adjustedInstallmentDueDate, periodStartDateApplicableForInterest,
|
||||||
periodStartDateApplicableForInterest, loanApplicationTerms.getLoanTermPeriodFrequencyType(),
|
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
|
||||||
loanApplicationTerms.getRepaymentEvery());
|
|
||||||
|
// ========================= Calculate the interest due
|
||||||
// ========================= Calculate the interest due ========================================
|
// ========================================
|
||||||
|
|
||||||
// change the principal to => Principal Disbursed - Total Principal Paid
|
// change the principal to => Principal Disbursed - Total
|
||||||
// interest calculation is always based on the total principal outstanding
|
// Principal Paid
|
||||||
loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
|
// interest calculation is always based on the total
|
||||||
|
// principal outstanding
|
||||||
// determine the interest & principal for the period
|
loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
|
||||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
|
||||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal,
|
// determine the interest & principal for the period
|
||||||
totalCumulativeInterest, totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||||
daysInInstallment, outstandingBalance, loanApplicationTerms, periodNumber, mathContext);
|
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||||
|
totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
||||||
// update the interest due for the period
|
totalOutstandingInterestPaymentDueToGrace, daysInInstallment, outstandingBalance, loanApplicationTerms,
|
||||||
period.updateInterestDue(principalInterestForThisPeriod.interest());
|
periodNumber, mathContext);
|
||||||
|
|
||||||
// =============================================================================================
|
// update the interest due for the period
|
||||||
|
period.updateInterestDue(principalInterestForThisPeriod.interest());
|
||||||
// ========================== Calculate the principal due ======================================
|
|
||||||
|
// =============================================================================================
|
||||||
// change the principal to => Principal Disbursed - Total cumulative Principal Amount before the reschedule installment
|
|
||||||
loanApplicationTerms.setPrincipal(principal.minus(totalPrincipalBeforeReschedulePeriod));
|
// ========================== Calculate the principal due
|
||||||
|
// ======================================
|
||||||
principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
|
||||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal,
|
// change the principal to => Principal Disbursed - Total
|
||||||
totalCumulativeInterest, totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
// cumulative Principal Amount before the reschedule
|
||||||
daysInInstallment, outstandingBalance, loanApplicationTerms, periodNumber, mathContext);
|
// installment
|
||||||
|
loanApplicationTerms.setPrincipal(principal.minus(totalPrincipalBeforeReschedulePeriod));
|
||||||
period.updatePrincipalDue(principalInterestForThisPeriod.principal());
|
|
||||||
|
principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(this.paymentPeriodsInOneYearCalculator,
|
||||||
// ==============================================================================================
|
interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal, totalCumulativeInterest,
|
||||||
|
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, daysInInstallment,
|
||||||
outstandingLoanBalance = outstandingLoanBalance.minus(period.principalDue());
|
outstandingBalance, loanApplicationTerms, periodNumber, mathContext);
|
||||||
period.updateOutstandingLoanBalance(outstandingLoanBalance);
|
|
||||||
|
period.updatePrincipalDue(principalInterestForThisPeriod.principal());
|
||||||
Money principalDue = Money.of(currency, period.principalDue());
|
|
||||||
Money interestDue = Money.of(currency, period.interestDue());
|
// ==============================================================================================
|
||||||
Money feeChargesDue = Money.of(currency, period.feeChargesDue());
|
|
||||||
Money penaltyChargesDue = Money.of(currency, period.penaltyChargesDue());
|
outstandingLoanBalance = outstandingLoanBalance.minus(period.principalDue());
|
||||||
|
period.updateOutstandingLoanBalance(outstandingLoanBalance);
|
||||||
Money totalDue = principalDue
|
|
||||||
.plus(interestDue)
|
Money principalDue = Money.of(currency, period.principalDue());
|
||||||
.plus(feeChargesDue)
|
Money interestDue = Money.of(currency, period.interestDue());
|
||||||
.plus(penaltyChargesDue);
|
Money feeChargesDue = Money.of(currency, period.feeChargesDue());
|
||||||
|
Money penaltyChargesDue = Money.of(currency, period.penaltyChargesDue());
|
||||||
period.updateTotalDue(totalDue);
|
|
||||||
|
Money totalDue = principalDue.plus(interestDue).plus(feeChargesDue).plus(penaltyChargesDue);
|
||||||
// update cumulative fields for principal & interest
|
|
||||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(period.principalDue());
|
period.updateTotalDue(totalDue);
|
||||||
totalCumulativeInterest = totalCumulativeInterest.plus(period.interestDue());
|
|
||||||
actualTotalCumulativeInterest = actualTotalCumulativeInterest.plus(period.interestDue());
|
// update cumulative fields for principal & interest
|
||||||
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
totalCumulativePrincipal = totalCumulativePrincipal.plus(period.principalDue());
|
||||||
|
totalCumulativeInterest = totalCumulativeInterest.plus(period.interestDue());
|
||||||
installmentFromDate = adjustedInstallmentDueDate;
|
actualTotalCumulativeInterest = actualTotalCumulativeInterest.plus(period.interestDue());
|
||||||
installmentNumber++;
|
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
||||||
periodNumber++;
|
|
||||||
loanTermInDays += daysInInstallment;
|
installmentFromDate = adjustedInstallmentDueDate;
|
||||||
|
installmentNumber++;
|
||||||
outstandingBalance = outstandingBalance.minus(period.principalDue());
|
periodNumber++;
|
||||||
}
|
loanTermInDays += daysInInstallment;
|
||||||
}
|
|
||||||
}
|
outstandingBalance = outstandingBalance.minus(period.principalDue());
|
||||||
|
}
|
||||||
final Money totalRepaymentExpected = principal // get the loan Principal amount
|
}
|
||||||
.plus(actualTotalCumulativeInterest) // add the actual total cumulative interest
|
}
|
||||||
.plus(loanSummary.getTotalFeeChargesCharged()) // add the total fees charged
|
|
||||||
.plus(loanSummary.getTotalPenaltyChargesCharged()); // finally add the total penalty charged
|
final Money totalRepaymentExpected = principal // get the loan Principal
|
||||||
|
// amount
|
||||||
return LoanRescheduleModel.instance(periods, loanRepaymentScheduleHistoryList, applicationCurrency, loanTermInDays,
|
.plus(actualTotalCumulativeInterest) // add the actual total
|
||||||
loan.getPrincpal(), loan.getPrincpal().getAmount(), loanSummary.getTotalPrincipalRepaid(), actualTotalCumulativeInterest.getAmount(),
|
// cumulative interest
|
||||||
loanSummary.getTotalFeeChargesCharged(), loanSummary.getTotalPenaltyChargesCharged(), totalRepaymentExpected.getAmount(),
|
.plus(loanSummary.getTotalFeeChargesCharged()) // add the total
|
||||||
loanSummary.getTotalOutstanding());
|
// fees charged
|
||||||
}
|
.plus(loanSummary.getTotalPenaltyChargesCharged()); // finally
|
||||||
|
// add the
|
||||||
private Collection<LoanRepaymentScheduleHistory> createLoanScheduleArchive(final LoanRescheduleRequest loanRescheduleRequest) {
|
// total
|
||||||
final Loan loan = loanRescheduleRequest.getLoan();
|
// penalty
|
||||||
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
// charged
|
||||||
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
|
||||||
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
return LoanRescheduleModel.instance(periods, loanRepaymentScheduleHistoryList, applicationCurrency, loanTermInDays,
|
||||||
List<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = new ArrayList<LoanRepaymentScheduleHistory>();
|
loan.getPrincpal(), loan.getPrincpal().getAmount(), loanSummary.getTotalPrincipalRepaid(),
|
||||||
|
actualTotalCumulativeInterest.getAmount(), loanSummary.getTotalFeeChargesCharged(),
|
||||||
for(LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
|
loanSummary.getTotalPenaltyChargesCharged(), totalRepaymentExpected.getAmount(), loanSummary.getTotalOutstanding());
|
||||||
final Integer installmentNumber = repaymentScheduleInstallment.getInstallmentNumber();
|
|
||||||
Date fromDate = null;
|
|
||||||
Date dueDate = null;
|
|
||||||
|
|
||||||
if(repaymentScheduleInstallment.getFromDate() != null) {
|
|
||||||
fromDate = repaymentScheduleInstallment.getFromDate().toDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(repaymentScheduleInstallment.getDueDate() != null) {
|
|
||||||
dueDate = repaymentScheduleInstallment.getDueDate().toDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
final BigDecimal principal = repaymentScheduleInstallment.getPrincipal(currency).getAmount();
|
|
||||||
final BigDecimal principalCompleted = repaymentScheduleInstallment.getPrincipalCompleted(currency).getAmount();
|
|
||||||
final BigDecimal principalWrittenOff = repaymentScheduleInstallment.getPrincipalWrittenOff(currency).getAmount();
|
|
||||||
final BigDecimal interestCharged = repaymentScheduleInstallment.getInterestCharged(currency).getAmount();
|
|
||||||
final BigDecimal interestPaid = repaymentScheduleInstallment.getInterestPaid(currency).getAmount();
|
|
||||||
final BigDecimal interestWaived = repaymentScheduleInstallment.getInterestWaived(currency).getAmount();
|
|
||||||
final BigDecimal interestWrittenOff = repaymentScheduleInstallment.getInterestWrittenOff(currency).getAmount();
|
|
||||||
final BigDecimal feeChargesCharged = repaymentScheduleInstallment.getFeeChargesCharged(currency).getAmount();
|
|
||||||
final BigDecimal feeChargesPaid = repaymentScheduleInstallment.getFeeChargesPaid(currency).getAmount();
|
|
||||||
final BigDecimal feeChargesWrittenOff = repaymentScheduleInstallment.getFeeChargesWrittenOff(currency).getAmount();
|
|
||||||
final BigDecimal feeChargesWaived = repaymentScheduleInstallment.getFeeChargesWaived(currency).getAmount();
|
|
||||||
final BigDecimal penaltyCharges = repaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount();
|
|
||||||
final BigDecimal penaltyChargesPaid = repaymentScheduleInstallment.getPenaltyChargesPaid(currency).getAmount();
|
|
||||||
final BigDecimal penaltyChargesWrittenOff = repaymentScheduleInstallment.getPenaltyChargesWrittenOff(currency).getAmount();
|
|
||||||
final BigDecimal penaltyChargesWaived = repaymentScheduleInstallment.getPenaltyChargesWaived(currency).getAmount();
|
|
||||||
final BigDecimal totalPaidInAdvance = repaymentScheduleInstallment.getTotalPaidInAdvance();
|
|
||||||
final BigDecimal totalPaidLate = repaymentScheduleInstallment.getTotalPaidLate();
|
|
||||||
final boolean obligationsMet = repaymentScheduleInstallment.isObligationsMet();
|
|
||||||
Date obligationsMetOnDate = null;
|
|
||||||
|
|
||||||
if(repaymentScheduleInstallment.getObligationsMetOnDate() != null) {
|
|
||||||
obligationsMetOnDate = repaymentScheduleInstallment.getObligationsMetOnDate().toDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
Date createdOnDate = null;
|
|
||||||
|
|
||||||
if(repaymentScheduleInstallment.getCreatedDate() != null) {
|
|
||||||
createdOnDate = repaymentScheduleInstallment.getCreatedDate().toDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
final AppUser createdByUser = repaymentScheduleInstallment.getCreatedBy();
|
|
||||||
final AppUser lastModifiedByUser = repaymentScheduleInstallment.getLastModifiedBy();
|
|
||||||
|
|
||||||
Date lastModifiedOnDate = null;
|
|
||||||
|
|
||||||
if(repaymentScheduleInstallment.getLastModifiedDate() != null) {
|
|
||||||
lastModifiedOnDate = repaymentScheduleInstallment.getLastModifiedDate().toDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
LoanRepaymentScheduleHistory loanRepaymentScheduleHistory = LoanRepaymentScheduleHistory.instance(loan,
|
|
||||||
loanRescheduleRequest, installmentNumber, fromDate, dueDate, principal, principalCompleted,
|
|
||||||
principalWrittenOff, interestCharged, interestPaid, interestWaived, interestWrittenOff,
|
|
||||||
feeChargesCharged, feeChargesPaid, feeChargesWrittenOff, feeChargesWaived, penaltyCharges,
|
|
||||||
penaltyChargesPaid, penaltyChargesWrittenOff, penaltyChargesWaived, totalPaidInAdvance, totalPaidLate,
|
|
||||||
obligationsMet, obligationsMetOnDate, createdOnDate, createdByUser, lastModifiedByUser, lastModifiedOnDate);
|
|
||||||
|
|
||||||
loanRepaymentScheduleHistoryList.add(loanRepaymentScheduleHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
return loanRepaymentScheduleHistoryList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal calculateInterestForSpecificDays(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
private BigDecimal calculateInterestForSpecificDays(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
||||||
@@ -1669,14 +1606,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
return precloseTransaction;
|
return precloseTransaction;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the value to zero if the provided value is null
|
* set the value to zero if the provided value is null
|
||||||
*
|
*
|
||||||
* @return integer value equal/greater than 0
|
* @return integer value equal/greater than 0
|
||||||
**/
|
**/
|
||||||
private Integer defaultToZeroIfNull(Integer value) {
|
private Integer defaultToZeroIfNull(Integer value) {
|
||||||
|
|
||||||
return (value != null) ? value : 0;
|
return (value != null) ? value : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* 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.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_loan_repayment_schedule_history")
|
||||||
|
public class LoanRepaymentScheduleHistory extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "loan_id")
|
||||||
|
private Loan loan;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@OneToOne(optional = true)
|
||||||
|
@JoinColumn(name = "loan_reschedule_request_id")
|
||||||
|
private LoanRescheduleRequest loanRescheduleRequest;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "installment", nullable = false)
|
||||||
|
private Integer installmentNumber;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
@Column(name = "fromdate", nullable = true)
|
||||||
|
private Date fromDate;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
@Column(name = "duedate", nullable = false)
|
||||||
|
private Date dueDate;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = true)
|
||||||
|
private BigDecimal principal;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "interest_amount", scale = 6, precision = 19, nullable = true)
|
||||||
|
private BigDecimal interestCharged;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||||
|
private BigDecimal feeChargesCharged;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "penalty_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||||
|
private BigDecimal penaltyCharges;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
@Column(name = "created_date")
|
||||||
|
private Date createdOnDate;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "createdby_id")
|
||||||
|
private AppUser createdByUser;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "lastmodifiedby_id")
|
||||||
|
private AppUser lastModifiedByUser;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
@Column(name = "lastmodified_date")
|
||||||
|
private Date lastModifiedOnDate;
|
||||||
|
|
||||||
|
@Column(name = "version")
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private Integer version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoanRepaymentScheduleHistory constructor
|
||||||
|
**/
|
||||||
|
protected LoanRepaymentScheduleHistory() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoanRepaymentScheduleHistory constructor
|
||||||
|
**/
|
||||||
|
private LoanRepaymentScheduleHistory(final Loan loan, final LoanRescheduleRequest loanRescheduleRequest,
|
||||||
|
final Integer installmentNumber, final Date fromDate, final Date dueDate, final BigDecimal principal,
|
||||||
|
final BigDecimal interestCharged, final BigDecimal feeChargesCharged, final BigDecimal penaltyCharges,
|
||||||
|
final Date createdOnDate, final AppUser createdByUser, final AppUser lastModifiedByUser, final Date lastModifiedOnDate,
|
||||||
|
final Integer version) {
|
||||||
|
|
||||||
|
this.loan = loan;
|
||||||
|
this.loanRescheduleRequest = loanRescheduleRequest;
|
||||||
|
this.installmentNumber = installmentNumber;
|
||||||
|
this.fromDate = fromDate;
|
||||||
|
this.dueDate = dueDate;
|
||||||
|
this.principal = principal;
|
||||||
|
this.interestCharged = interestCharged;
|
||||||
|
this.feeChargesCharged = feeChargesCharged;
|
||||||
|
this.penaltyCharges = penaltyCharges;
|
||||||
|
this.createdOnDate = createdOnDate;
|
||||||
|
this.createdByUser = createdByUser;
|
||||||
|
this.lastModifiedByUser = lastModifiedByUser;
|
||||||
|
this.lastModifiedOnDate = lastModifiedOnDate;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an instance of the LoanRepaymentScheduleHistory class
|
||||||
|
**/
|
||||||
|
public static LoanRepaymentScheduleHistory instance(final Loan loan, final LoanRescheduleRequest loanRescheduleRequest,
|
||||||
|
final Integer installmentNumber, final Date fromDate, final Date dueDate, final BigDecimal principal,
|
||||||
|
final BigDecimal interestCharged, final BigDecimal feeChargesCharged, final BigDecimal penaltyCharges,
|
||||||
|
final Date createdOnDate, final AppUser createdByUser, final AppUser lastModifiedByUser, final Date lastModifiedOnDate,
|
||||||
|
final Integer version) {
|
||||||
|
|
||||||
|
return new LoanRepaymentScheduleHistory(loan, loanRescheduleRequest, installmentNumber, fromDate, dueDate, principal,
|
||||||
|
interestCharged, feeChargesCharged, penaltyCharges, createdOnDate, createdByUser, lastModifiedByUser, lastModifiedOnDate,
|
||||||
|
version);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
* 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/.
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain;
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
|
|
||||||
|
public interface LoanScheduleHistoryReadPlatformService {
|
||||||
|
|
||||||
|
Integer fetchCurrentVersionNumber(Long loanId);
|
||||||
|
|
||||||
|
LoanScheduleData retrieveRepaymentArchiveSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
|
||||||
|
Collection<DisbursementData> disbursementData);
|
||||||
|
}
|
||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.joda.time.Days;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||||
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||||
|
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LoanScheduleHistoryReadPlatformServiceImpl implements LoanScheduleHistoryReadPlatformService {
|
||||||
|
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
private final PlatformSecurityContext context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public LoanScheduleHistoryReadPlatformServiceImpl(final RoutingDataSource dataSource, final PlatformSecurityContext context) {
|
||||||
|
this.context = context;
|
||||||
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer fetchCurrentVersionNumber(Long loanId) {
|
||||||
|
final String sql = "select MAX(lrs.version) from m_loan_repayment_schedule_history lrs where lrs.loan_id = ?";
|
||||||
|
return this.jdbcTemplate.queryForInt(sql, loanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoanScheduleData retrieveRepaymentArchiveSchedule(final Long loanId,
|
||||||
|
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.context.authenticatedUser();
|
||||||
|
Integer versionNumber = fetchCurrentVersionNumber(loanId);
|
||||||
|
if (versionNumber == 0) { return null; }
|
||||||
|
final LoanScheduleArchiveResultSetExtractor fullResultsetExtractor = new LoanScheduleArchiveResultSetExtractor(
|
||||||
|
repaymentScheduleRelatedLoanData, disbursementData);
|
||||||
|
final String sql = "select " + fullResultsetExtractor.schema()
|
||||||
|
+ " where ls.loan_id = ? and ls.version = ? order by ls.loan_id, ls.installment";
|
||||||
|
|
||||||
|
return this.jdbcTemplate.query(sql, fullResultsetExtractor, new Object[] { loanId, versionNumber });
|
||||||
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
|
throw new LoanNotFoundException(loanId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class LoanScheduleArchiveResultSetExtractor implements ResultSetExtractor<LoanScheduleData> {
|
||||||
|
|
||||||
|
private final CurrencyData currency;
|
||||||
|
private final DisbursementData disbursement;
|
||||||
|
private final BigDecimal totalFeeChargesDueAtDisbursement;
|
||||||
|
private final Collection<DisbursementData> disbursementData;
|
||||||
|
private LocalDate lastDueDate;
|
||||||
|
private BigDecimal outstandingLoanPrincipalBalance;
|
||||||
|
|
||||||
|
public LoanScheduleArchiveResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
|
||||||
|
Collection<DisbursementData> disbursementData) {
|
||||||
|
this.currency = repaymentScheduleRelatedLoanData.getCurrency();
|
||||||
|
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
||||||
|
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
||||||
|
this.lastDueDate = this.disbursement.disbursementDate();
|
||||||
|
this.outstandingLoanPrincipalBalance = this.disbursement.amount();
|
||||||
|
this.disbursementData = disbursementData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder(200);
|
||||||
|
stringBuilder.append(" ls.installment as period, ls.fromdate as fromDate, ls.duedate as dueDate, ");
|
||||||
|
stringBuilder
|
||||||
|
.append("ls.principal_amount as principalDue, ls.interest_amount as interestDue, ls.fee_charges_amount as feeChargesDue, ls.penalty_charges_amount as penaltyChargesDue ");
|
||||||
|
stringBuilder.append(" from m_loan_repayment_schedule_history ls ");
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoanScheduleData extractData(final ResultSet rs) throws SQLException, DataAccessException {
|
||||||
|
|
||||||
|
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
|
this.disbursement.disbursementDate(), this.disbursement.amount(), this.totalFeeChargesDueAtDisbursement,
|
||||||
|
this.disbursement.isDisbursed());
|
||||||
|
|
||||||
|
final Collection<LoanSchedulePeriodData> periods = new ArrayList<>();
|
||||||
|
final MonetaryCurrency monCurrency = new MonetaryCurrency(this.currency.code(), this.currency.decimalPlaces(),
|
||||||
|
this.currency.currencyInMultiplesOf());
|
||||||
|
BigDecimal totalPrincipalDisbursed = BigDecimal.ZERO;
|
||||||
|
if (disbursementData == null || disbursementData.isEmpty()) {
|
||||||
|
periods.add(disbursementPeriod);
|
||||||
|
totalPrincipalDisbursed = Money.of(monCurrency, this.disbursement.amount()).getAmount();
|
||||||
|
} else {
|
||||||
|
this.outstandingLoanPrincipalBalance = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
Money totalPrincipalExpected = Money.zero(monCurrency);
|
||||||
|
Money totalInterestCharged = Money.zero(monCurrency);
|
||||||
|
Money totalFeeChargesCharged = Money.zero(monCurrency);
|
||||||
|
Money totalPenaltyChargesCharged = Money.zero(monCurrency);
|
||||||
|
Money totalRepaymentExpected = Money.zero(monCurrency);
|
||||||
|
|
||||||
|
// update totals with details of fees charged during disbursement
|
||||||
|
totalFeeChargesCharged = totalFeeChargesCharged.plus(disbursementPeriod.feeChargesDue());
|
||||||
|
totalRepaymentExpected = totalRepaymentExpected.plus(disbursementPeriod.feeChargesDue());
|
||||||
|
|
||||||
|
Integer loanTermInDays = Integer.valueOf(0);
|
||||||
|
while (rs.next()) {
|
||||||
|
final Integer period = JdbcSupport.getInteger(rs, "period");
|
||||||
|
LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromDate");
|
||||||
|
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
|
||||||
|
if (disbursementData != null) {
|
||||||
|
BigDecimal principal = BigDecimal.ZERO;
|
||||||
|
for (DisbursementData data : disbursementData) {
|
||||||
|
if (fromDate.equals(this.disbursement.disbursementDate()) && data.disbursementDate().equals(fromDate)) {
|
||||||
|
principal = principal.add(data.amount());
|
||||||
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
|
data.disbursementDate(), data.amount(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed());
|
||||||
|
periods.add(periodData);
|
||||||
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||||
|
} else if (data.isDueForDisbursement(fromDate, dueDate)
|
||||||
|
&& this.outstandingLoanPrincipalBalance.compareTo(BigDecimal.ZERO) == 1) {
|
||||||
|
principal = principal.add(data.amount());
|
||||||
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
|
data.disbursementDate(), data.amount(), BigDecimal.ZERO, data.isDisbursed());
|
||||||
|
periods.add(periodData);
|
||||||
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalPrincipalDisbursed = totalPrincipalDisbursed.add(principal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer daysInPeriod = Integer.valueOf(0);
|
||||||
|
if (fromDate != null) {
|
||||||
|
daysInPeriod = Days.daysBetween(fromDate, dueDate).getDays();
|
||||||
|
loanTermInDays = Integer.valueOf(loanTermInDays.intValue() + daysInPeriod.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDue");
|
||||||
|
totalPrincipalExpected = totalPrincipalExpected.plus(principalDue);
|
||||||
|
|
||||||
|
final BigDecimal interestExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestDue");
|
||||||
|
totalInterestCharged = totalInterestCharged.plus(interestExpectedDue);
|
||||||
|
|
||||||
|
final BigDecimal feeChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesDue");
|
||||||
|
totalFeeChargesCharged = totalFeeChargesCharged.plus(feeChargesExpectedDue);
|
||||||
|
|
||||||
|
final BigDecimal penaltyChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesDue");
|
||||||
|
totalPenaltyChargesCharged = totalPenaltyChargesCharged.plus(penaltyChargesExpectedDue);
|
||||||
|
|
||||||
|
final BigDecimal totalExpectedCostOfLoanForPeriod = interestExpectedDue.add(feeChargesExpectedDue).add(
|
||||||
|
penaltyChargesExpectedDue);
|
||||||
|
|
||||||
|
final BigDecimal totalDueForPeriod = principalDue.add(totalExpectedCostOfLoanForPeriod);
|
||||||
|
|
||||||
|
totalRepaymentExpected = totalRepaymentExpected.plus(totalDueForPeriod);
|
||||||
|
|
||||||
|
if (fromDate == null) {
|
||||||
|
fromDate = this.lastDueDate;
|
||||||
|
}
|
||||||
|
final BigDecimal outstandingPrincipalBalanceOfLoan = this.outstandingLoanPrincipalBalance.subtract(principalDue);
|
||||||
|
|
||||||
|
// update based on current period values
|
||||||
|
this.lastDueDate = dueDate;
|
||||||
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.subtract(principalDue);
|
||||||
|
|
||||||
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.repaymentOnlyPeriod(period, fromDate, dueDate,
|
||||||
|
principalDue, outstandingPrincipalBalanceOfLoan, interestExpectedDue, feeChargesExpectedDue,
|
||||||
|
penaltyChargesExpectedDue, totalDueForPeriod);
|
||||||
|
|
||||||
|
periods.add(periodData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LoanScheduleData(this.currency, periods, loanTermInDays, totalPrincipalDisbursed,
|
||||||
|
totalPrincipalExpected.getAmount(), totalInterestCharged.getAmount(), totalFeeChargesCharged.getAmount(),
|
||||||
|
totalPenaltyChargesCharged.getAmount(), totalRepaymentExpected.getAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
|
|
||||||
|
public interface LoanScheduleHistoryWritePlatformService {
|
||||||
|
|
||||||
|
List<LoanRepaymentScheduleHistory> createLoanScheduleArchive(
|
||||||
|
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final Loan loan,
|
||||||
|
final LoanRescheduleRequest loanRescheduleRequest);
|
||||||
|
|
||||||
|
void createAndSaveLoanScheduleArchive(List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Loan loan,
|
||||||
|
LoanRescheduleRequest loanRescheduleRequest);
|
||||||
|
|
||||||
|
}
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistoryRepository;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LoanScheduleHistoryWritePlatformServiceImpl implements LoanScheduleHistoryWritePlatformService {
|
||||||
|
|
||||||
|
private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService;
|
||||||
|
private final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public LoanScheduleHistoryWritePlatformServiceImpl(final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService,
|
||||||
|
final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository) {
|
||||||
|
this.loanScheduleHistoryReadPlatformService = loanScheduleHistoryReadPlatformService;
|
||||||
|
this.loanRepaymentScheduleHistoryRepository = loanRepaymentScheduleHistoryRepository;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<LoanRepaymentScheduleHistory> createLoanScheduleArchive(
|
||||||
|
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Loan loan, LoanRescheduleRequest loanRescheduleRequest) {
|
||||||
|
Integer version = this.loanScheduleHistoryReadPlatformService.fetchCurrentVersionNumber(loan.getId()) + 1;
|
||||||
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
|
final List<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
|
||||||
|
final Integer installmentNumber = repaymentScheduleInstallment.getInstallmentNumber();
|
||||||
|
Date fromDate = null;
|
||||||
|
Date dueDate = null;
|
||||||
|
|
||||||
|
if (repaymentScheduleInstallment.getFromDate() != null) {
|
||||||
|
fromDate = repaymentScheduleInstallment.getFromDate().toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repaymentScheduleInstallment.getDueDate() != null) {
|
||||||
|
dueDate = repaymentScheduleInstallment.getDueDate().toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
final BigDecimal principal = repaymentScheduleInstallment.getPrincipal(currency).getAmount();
|
||||||
|
final BigDecimal interestCharged = repaymentScheduleInstallment.getInterestCharged(currency).getAmount();
|
||||||
|
final BigDecimal feeChargesCharged = repaymentScheduleInstallment.getFeeChargesCharged(currency).getAmount();
|
||||||
|
final BigDecimal penaltyCharges = repaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount();
|
||||||
|
|
||||||
|
Date createdOnDate = null;
|
||||||
|
if (repaymentScheduleInstallment.getCreatedDate() != null) {
|
||||||
|
createdOnDate = repaymentScheduleInstallment.getCreatedDate().toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
final AppUser createdByUser = repaymentScheduleInstallment.getCreatedBy();
|
||||||
|
final AppUser lastModifiedByUser = repaymentScheduleInstallment.getLastModifiedBy();
|
||||||
|
|
||||||
|
Date lastModifiedOnDate = null;
|
||||||
|
|
||||||
|
if (repaymentScheduleInstallment.getLastModifiedDate() != null) {
|
||||||
|
lastModifiedOnDate = repaymentScheduleInstallment.getLastModifiedDate().toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
LoanRepaymentScheduleHistory loanRepaymentScheduleHistory = LoanRepaymentScheduleHistory.instance(loan, loanRescheduleRequest,
|
||||||
|
installmentNumber, fromDate, dueDate, principal, interestCharged, feeChargesCharged, penaltyCharges, createdOnDate,
|
||||||
|
createdByUser, lastModifiedByUser, lastModifiedOnDate, version);
|
||||||
|
|
||||||
|
loanRepaymentScheduleHistoryList.add(loanRepaymentScheduleHistory);
|
||||||
|
}
|
||||||
|
return loanRepaymentScheduleHistoryList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createAndSaveLoanScheduleArchive(List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Loan loan,
|
||||||
|
LoanRescheduleRequest loanRescheduleRequest) {
|
||||||
|
List<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = createLoanScheduleArchive(repaymentScheduleInstallments,
|
||||||
|
loan, loanRescheduleRequest);
|
||||||
|
this.loanRepaymentScheduleHistoryRepository.save(loanRepaymentScheduleHistoryList);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
-210
@@ -1,210 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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.loanaccount.rescheduleloan.domain;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.JoinColumn;
|
|
||||||
import javax.persistence.ManyToOne;
|
|
||||||
import javax.persistence.OneToOne;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
import javax.persistence.Temporal;
|
|
||||||
import javax.persistence.TemporalType;
|
|
||||||
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
|
||||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "m_loan_repayment_schedule_history")
|
|
||||||
public class LoanRepaymentScheduleHistory extends AbstractPersistable<Long> {
|
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
|
||||||
@JoinColumn(name = "loan_id")
|
|
||||||
private Loan loan;
|
|
||||||
|
|
||||||
@OneToOne(optional = true)
|
|
||||||
@JoinColumn(name = "loan_reschedule_request_id")
|
|
||||||
private LoanRescheduleRequest loanRescheduleRequest;
|
|
||||||
|
|
||||||
@Column(name = "installment", nullable = false)
|
|
||||||
private Integer installmentNumber;
|
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
|
||||||
@Column(name = "fromdate", nullable = true)
|
|
||||||
private Date fromDate;
|
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
|
||||||
@Column(name = "duedate", nullable = false)
|
|
||||||
private Date dueDate;
|
|
||||||
|
|
||||||
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal principal;
|
|
||||||
|
|
||||||
@Column(name = "principal_completed_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal principalCompleted;
|
|
||||||
|
|
||||||
@Column(name = "principal_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal principalWrittenOff;
|
|
||||||
|
|
||||||
@Column(name = "interest_amount", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal interestCharged;
|
|
||||||
|
|
||||||
@Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal interestPaid;
|
|
||||||
|
|
||||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal interestWaived;
|
|
||||||
|
|
||||||
@Column(name = "interest_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal interestWrittenOff;
|
|
||||||
|
|
||||||
@Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal feeChargesCharged;
|
|
||||||
|
|
||||||
@Column(name = "fee_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal feeChargesPaid;
|
|
||||||
|
|
||||||
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal feeChargesWrittenOff;
|
|
||||||
|
|
||||||
@Column(name = "fee_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal feeChargesWaived;
|
|
||||||
|
|
||||||
@Column(name = "penalty_charges_amount", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal penaltyCharges;
|
|
||||||
|
|
||||||
@Column(name = "penalty_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal penaltyChargesPaid;
|
|
||||||
|
|
||||||
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal penaltyChargesWrittenOff;
|
|
||||||
|
|
||||||
@Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal penaltyChargesWaived;
|
|
||||||
|
|
||||||
@Column(name = "total_paid_in_advance_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal totalPaidInAdvance;
|
|
||||||
|
|
||||||
@Column(name = "total_paid_late_derived", scale = 6, precision = 19, nullable = true)
|
|
||||||
private BigDecimal totalPaidLate;
|
|
||||||
|
|
||||||
@Column(name = "completed_derived", nullable = false)
|
|
||||||
private boolean obligationsMet;
|
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
|
||||||
@Column(name = "obligations_met_on_date")
|
|
||||||
private Date obligationsMetOnDate;
|
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
|
||||||
@Column(name = "created_date")
|
|
||||||
private Date createdOnDate;
|
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(name = "createdby_id")
|
|
||||||
private AppUser createdByUser;
|
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(name = "lastmodifiedby_id")
|
|
||||||
private AppUser lastModifiedByUser;
|
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
|
||||||
@Column(name = "lastmodified_date")
|
|
||||||
private Date lastModifiedOnDate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LoanRepaymentScheduleHistory constructor
|
|
||||||
**/
|
|
||||||
protected LoanRepaymentScheduleHistory() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LoanRepaymentScheduleHistory constructor
|
|
||||||
**/
|
|
||||||
private LoanRepaymentScheduleHistory(final Loan loan, final LoanRescheduleRequest loanRescheduleRequest,
|
|
||||||
final Integer installmentNumber, final Date fromDate, final Date dueDate, final BigDecimal principal,
|
|
||||||
final BigDecimal principalCompleted, final BigDecimal principalWrittenOff, final BigDecimal interestCharged,
|
|
||||||
final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWrittenOff,
|
|
||||||
final BigDecimal feeChargesCharged, final BigDecimal feeChargesPaid, final BigDecimal feeChargesWrittenOff,
|
|
||||||
final BigDecimal feeChargesWaived, final BigDecimal penaltyCharges, final BigDecimal penaltyChargesPaid,
|
|
||||||
final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesWaived,
|
|
||||||
final BigDecimal totalPaidInAdvance, final BigDecimal totalPaidLate, final boolean obligationsMet,
|
|
||||||
final Date obligationsMetOnDate, final Date createdOnDate, final AppUser createdByUser,
|
|
||||||
final AppUser lastModifiedByUser, final Date lastModifiedOnDate) {
|
|
||||||
|
|
||||||
this.loan = loan;
|
|
||||||
this.loanRescheduleRequest = loanRescheduleRequest;
|
|
||||||
this.installmentNumber = installmentNumber;
|
|
||||||
this.fromDate = fromDate;
|
|
||||||
this.dueDate = dueDate;
|
|
||||||
this.principal = principal;
|
|
||||||
this.principalCompleted = principalCompleted;
|
|
||||||
this.principalWrittenOff = principalWrittenOff;
|
|
||||||
this.interestCharged = interestCharged;
|
|
||||||
this.interestPaid = interestPaid;
|
|
||||||
this.interestWaived = interestWaived;
|
|
||||||
this.interestWrittenOff = interestWrittenOff;
|
|
||||||
this.feeChargesCharged = feeChargesCharged;
|
|
||||||
this.feeChargesPaid = feeChargesPaid;
|
|
||||||
this.feeChargesWrittenOff = feeChargesWrittenOff;
|
|
||||||
this.feeChargesWaived = feeChargesWaived;
|
|
||||||
this.penaltyCharges = penaltyCharges;
|
|
||||||
this.penaltyChargesPaid = penaltyChargesPaid;
|
|
||||||
this.penaltyChargesWrittenOff = penaltyChargesWrittenOff;
|
|
||||||
this.penaltyChargesWaived = penaltyChargesWaived;
|
|
||||||
this.totalPaidInAdvance = totalPaidInAdvance;
|
|
||||||
this.totalPaidLate = totalPaidLate;
|
|
||||||
this.obligationsMet = obligationsMet;
|
|
||||||
this.obligationsMetOnDate = obligationsMetOnDate;
|
|
||||||
this.createdOnDate = createdOnDate;
|
|
||||||
this.createdByUser = createdByUser;
|
|
||||||
this.lastModifiedByUser = lastModifiedByUser;
|
|
||||||
this.lastModifiedOnDate = lastModifiedOnDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return an instance of the LoanRepaymentScheduleHistory class
|
|
||||||
**/
|
|
||||||
public static LoanRepaymentScheduleHistory instance(final Loan loan, final LoanRescheduleRequest loanRescheduleRequest,
|
|
||||||
final Integer installmentNumber, final Date fromDate, final Date dueDate, final BigDecimal principal,
|
|
||||||
final BigDecimal principalCompleted, final BigDecimal principalWrittenOff, final BigDecimal interestCharged,
|
|
||||||
final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWrittenOff,
|
|
||||||
final BigDecimal feeChargesCharged, final BigDecimal feeChargesPaid, final BigDecimal feeChargesWrittenOff,
|
|
||||||
final BigDecimal feeChargesWaived, final BigDecimal penaltyCharges, final BigDecimal penaltyChargesPaid,
|
|
||||||
final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesWaived,
|
|
||||||
final BigDecimal totalPaidInAdvance, final BigDecimal totalPaidLate, final boolean obligationsMet,
|
|
||||||
final Date obligationsMetOnDate, final Date createdOnDate, final AppUser createdByUser,
|
|
||||||
final AppUser lastModifiedByUser, final Date lastModifiedOnDate) {
|
|
||||||
|
|
||||||
return new LoanRepaymentScheduleHistory(loan, loanRescheduleRequest, installmentNumber, fromDate, dueDate, principal,
|
|
||||||
principalCompleted, principalWrittenOff, interestCharged, interestPaid, interestWaived, interestWrittenOff,
|
|
||||||
feeChargesCharged, feeChargesPaid, feeChargesWrittenOff, feeChargesWaived, penaltyCharges, penaltyChargesPaid,
|
|
||||||
penaltyChargesWrittenOff, penaltyChargesWaived, totalPaidInAdvance, totalPaidLate, obligationsMet,
|
|
||||||
obligationsMetOnDate, createdOnDate, createdByUser, lastModifiedByUser, lastModifiedOnDate);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static void create(final Loan loan, final LoanRescheduleRequest loanRescheduleRequest,
|
|
||||||
final Integer installmentNumber, final Date fromDate, final Date dueDate, final BigDecimal principal,
|
|
||||||
final BigDecimal principalCompleted, final BigDecimal principalWrittenOff, final BigDecimal interestCharged,
|
|
||||||
final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWrittenOff,
|
|
||||||
final BigDecimal feeChargesCharged, final BigDecimal feeChargesPaid, final BigDecimal feeChargesWrittenOff,
|
|
||||||
final BigDecimal feeChargesWaived, final BigDecimal penaltyCharges, final BigDecimal penaltyChargesPaid,
|
|
||||||
final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesWaived,
|
|
||||||
final BigDecimal totalPaidInAdvance, final BigDecimal totalPaidLate, final boolean obligationsMet,
|
|
||||||
final Date obligationsMetOnDate, final Date createdOnDate, final AppUser createdByUser,
|
|
||||||
final AppUser lastModifiedByUser, final Date lastModifiedOnDate) {
|
|
||||||
|
|
||||||
new LoanRepaymentScheduleHistory(loan, loanRescheduleRequest, installmentNumber, fromDate, dueDate, principal,
|
|
||||||
principalCompleted, principalWrittenOff, interestCharged, interestPaid, interestWaived, interestWrittenOff,
|
|
||||||
feeChargesCharged, feeChargesPaid, feeChargesWrittenOff, feeChargesWaived, penaltyCharges, penaltyChargesPaid,
|
|
||||||
penaltyChargesWrittenOff, penaltyChargesWaived, totalPaidInAdvance, totalPaidLate, obligationsMet,
|
|
||||||
obligationsMetOnDate, createdOnDate, createdByUser, lastModifiedByUser, lastModifiedOnDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+38
-26
@@ -14,13 +14,14 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
|||||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
||||||
|
|
||||||
public final class LoanRescheduleModel {
|
public final class LoanRescheduleModel {
|
||||||
|
|
||||||
private final Collection<LoanRescheduleModelRepaymentPeriod> periods;
|
private final Collection<LoanRescheduleModelRepaymentPeriod> periods;
|
||||||
private final Collection<LoanRepaymentScheduleHistory> oldPeriods;
|
private final Collection<LoanRepaymentScheduleHistory> oldPeriods;
|
||||||
private final ApplicationCurrency applicationCurrency;
|
private final ApplicationCurrency applicationCurrency;
|
||||||
private final int loanTermInDays;
|
private final int loanTermInDays;
|
||||||
private final Money totalPrincipalDisbursed;
|
private final Money totalPrincipalDisbursed;
|
||||||
private final BigDecimal totalPrincipalExpected;
|
private final BigDecimal totalPrincipalExpected;
|
||||||
private final BigDecimal totalPrincipalPaid;
|
private final BigDecimal totalPrincipalPaid;
|
||||||
@@ -29,14 +30,14 @@ public final class LoanRescheduleModel {
|
|||||||
private final BigDecimal totalPenaltyChargesCharged;
|
private final BigDecimal totalPenaltyChargesCharged;
|
||||||
private final BigDecimal totalRepaymentExpected;
|
private final BigDecimal totalRepaymentExpected;
|
||||||
private final BigDecimal totalOutstanding;
|
private final BigDecimal totalOutstanding;
|
||||||
|
|
||||||
public LoanRescheduleModel(final Collection<LoanRescheduleModelRepaymentPeriod> periods, final Collection<LoanRepaymentScheduleHistory> oldPeriods,
|
private LoanRescheduleModel(final Collection<LoanRescheduleModelRepaymentPeriod> periods,
|
||||||
final ApplicationCurrency applicationCurrency, final int loanTermInDays, final Money principalDisbursed,
|
final Collection<LoanRepaymentScheduleHistory> oldPeriods, final ApplicationCurrency applicationCurrency,
|
||||||
final BigDecimal totalPrincipalExpected, final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged,
|
final int loanTermInDays, final Money principalDisbursed, final BigDecimal totalPrincipalExpected,
|
||||||
final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected,
|
final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged,
|
||||||
final BigDecimal totalOutstanding) {
|
final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
||||||
this.periods = periods;
|
this.periods = periods;
|
||||||
this.oldPeriods = oldPeriods;
|
this.oldPeriods = oldPeriods;
|
||||||
this.applicationCurrency = applicationCurrency;
|
this.applicationCurrency = applicationCurrency;
|
||||||
this.loanTermInDays = loanTermInDays;
|
this.loanTermInDays = loanTermInDays;
|
||||||
this.totalPrincipalDisbursed = principalDisbursed;
|
this.totalPrincipalDisbursed = principalDisbursed;
|
||||||
@@ -48,25 +49,36 @@ public final class LoanRescheduleModel {
|
|||||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||||
this.totalOutstanding = totalOutstanding;
|
this.totalOutstanding = totalOutstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanRescheduleModel instance(final Collection<LoanRescheduleModelRepaymentPeriod> periods, final Collection<LoanRepaymentScheduleHistory> oldPeriods,
|
public static LoanRescheduleModel instance(final Collection<LoanRescheduleModelRepaymentPeriod> periods,
|
||||||
final ApplicationCurrency applicationCurrency, final int loanTermInDays, final Money principalDisbursed,
|
final Collection<LoanRepaymentScheduleHistory> oldPeriods, final ApplicationCurrency applicationCurrency,
|
||||||
final BigDecimal totalPrincipalExpected, final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged,
|
final int loanTermInDays, final Money principalDisbursed, final BigDecimal totalPrincipalExpected,
|
||||||
final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected,
|
final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged,
|
||||||
final BigDecimal totalOutstanding) {
|
final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
||||||
|
|
||||||
return new LoanRescheduleModel(periods, oldPeriods, applicationCurrency, loanTermInDays, principalDisbursed, totalPrincipalExpected,
|
return new LoanRescheduleModel(periods, oldPeriods, applicationCurrency, loanTermInDays, principalDisbursed,
|
||||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
totalPrincipalExpected, totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||||
totalRepaymentExpected, totalOutstanding);
|
totalRepaymentExpected, totalOutstanding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LoanRescheduleModel createWithSchedulehistory(LoanRescheduleModel loanRescheduleModel,
|
||||||
|
final Collection<LoanRepaymentScheduleHistory> oldPeriods) {
|
||||||
|
|
||||||
|
return new LoanRescheduleModel(loanRescheduleModel.periods, oldPeriods, loanRescheduleModel.applicationCurrency,
|
||||||
|
loanRescheduleModel.loanTermInDays, loanRescheduleModel.totalPrincipalDisbursed,
|
||||||
|
loanRescheduleModel.totalPrincipalExpected, loanRescheduleModel.totalPrincipalPaid,
|
||||||
|
loanRescheduleModel.totalInterestCharged, loanRescheduleModel.totalFeeChargesCharged,
|
||||||
|
loanRescheduleModel.totalPenaltyChargesCharged, loanRescheduleModel.totalRepaymentExpected,
|
||||||
|
loanRescheduleModel.totalOutstanding);
|
||||||
|
}
|
||||||
|
|
||||||
public LoanScheduleData toData() {
|
public LoanScheduleData toData() {
|
||||||
|
|
||||||
final int decimalPlaces = this.totalPrincipalDisbursed.getCurrencyDigitsAfterDecimal();
|
final int decimalPlaces = this.totalPrincipalDisbursed.getCurrencyDigitsAfterDecimal();
|
||||||
final Integer inMultiplesOf = this.totalPrincipalDisbursed.getCurrencyInMultiplesOf();
|
final Integer inMultiplesOf = this.totalPrincipalDisbursed.getCurrencyInMultiplesOf();
|
||||||
final CurrencyData currency = this.applicationCurrency.toData(decimalPlaces, inMultiplesOf);
|
final CurrencyData currency = this.applicationCurrency.toData(decimalPlaces, inMultiplesOf);
|
||||||
|
|
||||||
final Collection<LoanSchedulePeriodData> periodsData = new ArrayList<LoanSchedulePeriodData>();
|
final Collection<LoanSchedulePeriodData> periodsData = new ArrayList<>();
|
||||||
for (final LoanRescheduleModalPeriod modelPeriod : this.periods) {
|
for (final LoanRescheduleModalPeriod modelPeriod : this.periods) {
|
||||||
periodsData.add(modelPeriod.toData());
|
periodsData.add(modelPeriod.toData());
|
||||||
}
|
}
|
||||||
@@ -82,12 +94,12 @@ public final class LoanRescheduleModel {
|
|||||||
this.totalPenaltyChargesCharged, totalWaived, totalWrittenOff, this.totalRepaymentExpected, totalRepayment,
|
this.totalPenaltyChargesCharged, totalWaived, totalWrittenOff, this.totalRepaymentExpected, totalRepayment,
|
||||||
totalPaidInAdvance, totalPaidLate, this.totalOutstanding);
|
totalPaidInAdvance, totalPaidLate, this.totalOutstanding);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<LoanRescheduleModelRepaymentPeriod> getPeriods() {
|
public Collection<LoanRescheduleModelRepaymentPeriod> getPeriods() {
|
||||||
return this.periods;
|
return this.periods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<LoanRepaymentScheduleHistory> getOldPeriods() {
|
public Collection<LoanRepaymentScheduleHistory> getOldPeriods() {
|
||||||
return this.oldPeriods;
|
return this.oldPeriods;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-40
@@ -19,6 +19,8 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
|||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
@@ -31,52 +33,54 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class LoanReschedulePreviewPlatformServiceImpl implements LoanReschedulePreviewPlatformService {
|
public class LoanReschedulePreviewPlatformServiceImpl implements LoanReschedulePreviewPlatformService {
|
||||||
|
|
||||||
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
|
|
||||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
|
||||||
private final ConfigurationDomainService configurationDomainService;
|
|
||||||
private final HolidayRepository holidayRepository;
|
|
||||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
|
|
||||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
|
||||||
final ConfigurationDomainService configurationDomainService,
|
|
||||||
final HolidayRepository holidayRepository,
|
|
||||||
final WorkingDaysRepositoryWrapper workingDaysRepository) {
|
|
||||||
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
|
||||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
|
||||||
this.configurationDomainService = configurationDomainService;
|
|
||||||
this.holidayRepository = holidayRepository;
|
|
||||||
this.workingDaysRepository = workingDaysRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
|
||||||
public LoanRescheduleModel previewLoanReschedule(Long requestId) {
|
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
||||||
final LoanRescheduleRequest loanRescheduleRequest = this.loanRescheduleRequestRepository.findOne(requestId);
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
|
private final HolidayRepository holidayRepository;
|
||||||
if(loanRescheduleRequest == null) {
|
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||||
throw new LoanRescheduleRequestNotFoundException(requestId);
|
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
||||||
}
|
|
||||||
|
@Autowired
|
||||||
Loan loan = loanRescheduleRequest.getLoan();
|
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
|
||||||
|
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
||||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository,
|
||||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
|
final WorkingDaysRepositoryWrapper workingDaysRepository,
|
||||||
loan.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService) {
|
||||||
|
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
||||||
|
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||||
|
this.configurationDomainService = configurationDomainService;
|
||||||
|
this.holidayRepository = holidayRepository;
|
||||||
|
this.workingDaysRepository = workingDaysRepository;
|
||||||
|
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoanRescheduleModel previewLoanReschedule(Long requestId) {
|
||||||
|
final LoanRescheduleRequest loanRescheduleRequest = this.loanRescheduleRequestRepository.findOne(requestId);
|
||||||
|
|
||||||
|
if (loanRescheduleRequest == null) { throw new LoanRescheduleRequestNotFoundException(requestId); }
|
||||||
|
|
||||||
|
Loan loan = loanRescheduleRequest.getLoan();
|
||||||
|
|
||||||
|
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
|
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
|
||||||
|
.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
||||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
||||||
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
||||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||||
|
|
||||||
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
||||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||||
final MathContext mathContext = new MathContext(8, roundingMode);
|
final MathContext mathContext = new MathContext(8, roundingMode);
|
||||||
|
List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive(
|
||||||
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
||||||
loanRescheduleRequest, applicationCurrency, isHolidayEnabled, holidays, workingDays);
|
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
||||||
|
loanRescheduleRequest, applicationCurrency, isHolidayEnabled, holidays, workingDays);
|
||||||
return loanRescheduleModel;
|
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
|
||||||
}
|
oldPeriods);
|
||||||
|
return loanRescheduleModelWithOldPeriods;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+390
-411
@@ -8,14 +8,11 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.service;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.joda.time.format.DateTimeFormat;
|
import org.joda.time.format.DateTimeFormat;
|
||||||
@@ -37,35 +34,25 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
|||||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummary;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummary;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistoryRepository;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestDataValidator;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestDataValidator;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRepaymentScheduleHistory;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRepaymentScheduleHistoryRepository;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
|
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -76,404 +63,396 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanRescheduleRequestWritePlatformService {
|
public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanRescheduleRequestWritePlatformService {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(LoanRescheduleRequestWritePlatformServiceImpl.class);
|
|
||||||
|
|
||||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
|
||||||
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
|
|
||||||
private final PlatformSecurityContext platformSecurityContext;
|
|
||||||
private final LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator;
|
|
||||||
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
|
|
||||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
|
||||||
private final ConfigurationDomainService configurationDomainService;
|
|
||||||
private final HolidayRepository holidayRepository;
|
|
||||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
|
||||||
private final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LoanRescheduleRequestWritePlatformServiceImpl constructor
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
@Autowired
|
|
||||||
public LoanRescheduleRequestWritePlatformServiceImpl(LoanRepositoryWrapper loanRepositoryWrapper,
|
|
||||||
CodeValueRepositoryWrapper codeValueRepositoryWrapper,
|
|
||||||
PlatformSecurityContext platformSecurityContext,
|
|
||||||
LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator,
|
|
||||||
LoanRescheduleRequestRepository loanRescheduleRequestRepository,
|
|
||||||
ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
|
||||||
ConfigurationDomainService configurationDomainService,
|
|
||||||
HolidayRepository holidayRepository,
|
|
||||||
WorkingDaysRepositoryWrapper workingDaysRepository,
|
|
||||||
LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository) {
|
|
||||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
|
||||||
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
|
|
||||||
this.platformSecurityContext = platformSecurityContext;
|
|
||||||
this.loanRescheduleRequestDataValidator = loanRescheduleRequestDataValidator;
|
|
||||||
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
|
||||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
|
||||||
this.configurationDomainService = configurationDomainService;
|
|
||||||
this.holidayRepository = holidayRepository;
|
|
||||||
this.workingDaysRepository = workingDaysRepository;
|
|
||||||
this.loanRepaymentScheduleHistoryRepository = loanRepaymentScheduleHistoryRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private final static Logger logger = LoggerFactory.getLogger(LoanRescheduleRequestWritePlatformServiceImpl.class);
|
||||||
* create a new instance of the LoanRescheduleRequest object from the JsonCommand object
|
|
||||||
* and persist
|
|
||||||
*
|
|
||||||
* @return CommandProcessingResult object
|
|
||||||
**/
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public CommandProcessingResult create(JsonCommand jsonCommand) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
// get the loan id from the JsonCommand object
|
|
||||||
final Long loanId = jsonCommand.longValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.loanIdParamName);
|
|
||||||
|
|
||||||
// use the loan id to get a Loan entity object
|
|
||||||
final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
|
|
||||||
|
|
||||||
// validate the request in the JsonCommand object passed as parameter
|
|
||||||
this.loanRescheduleRequestDataValidator.validateForCreateAction(jsonCommand, loan);
|
|
||||||
|
|
||||||
// get the reschedule reason code value id from the JsonCommand object
|
|
||||||
final Long rescheduleReasonId = jsonCommand.longValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.rescheduleReasonIdParamName);
|
|
||||||
|
|
||||||
// use the reschedule reason code value id to get a CodeValue entity object
|
|
||||||
final CodeValue rescheduleReasonCodeValue = this.codeValueRepositoryWrapper
|
|
||||||
.findOneWithNotFoundDetection(rescheduleReasonId);
|
|
||||||
|
|
||||||
// get the grace on principal integer value from the JsonCommand object
|
|
||||||
final Integer graceOnPrincipal = jsonCommand.integerValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.graceOnPrincipalParamName);
|
|
||||||
|
|
||||||
// get the grace on interest integer value from the JsonCommand object
|
|
||||||
final Integer graceOnInterest = jsonCommand.integerValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.graceOnInterestParamName);
|
|
||||||
|
|
||||||
// get the extra terms to be added at the end of the new schedule from the JsonCommand object
|
|
||||||
final Integer extraTerms = jsonCommand.integerValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.extraTermsParamName);
|
|
||||||
|
|
||||||
// get the new interest rate that would be applied to the new loan schedule
|
|
||||||
final BigDecimal interestRate = jsonCommand.bigDecimalValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.newInterestRateParamName);
|
|
||||||
|
|
||||||
// get the reschedule reason comment text from the JsonCommand object
|
|
||||||
final String rescheduleReasonComment = jsonCommand.stringValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.rescheduleReasonCommentParamName);
|
|
||||||
|
|
||||||
// get the recalculate interest option
|
|
||||||
final Boolean recalculateInterest = jsonCommand.booleanObjectValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.recalculateInterestParamName);
|
|
||||||
|
|
||||||
// initialize set the value to null
|
|
||||||
Date submittedOnDate = null;
|
|
||||||
|
|
||||||
// check if the parameter is in the JsonCommand object
|
|
||||||
if(jsonCommand.hasParameter(RescheduleLoansApiConstants.submittedOnDateParamName)) {
|
|
||||||
// create a LocalDate object from the "submittedOnDate" Date string
|
|
||||||
LocalDate localDate = jsonCommand.localDateValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.submittedOnDateParamName);
|
|
||||||
|
|
||||||
if(localDate != null) {
|
|
||||||
// update the value of the "submittedOnDate" variable
|
|
||||||
submittedOnDate = localDate.toDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initially set the value to null
|
|
||||||
Date rescheduleFromDate = null;
|
|
||||||
|
|
||||||
// start point of the rescheduling exercise
|
|
||||||
Integer rescheduleFromInstallment = null;
|
|
||||||
|
|
||||||
// initially set the value to null
|
|
||||||
Date adjustedDueDate = null;
|
|
||||||
|
|
||||||
// check if the parameter is in the JsonCommand object
|
|
||||||
if(jsonCommand.hasParameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)) {
|
|
||||||
// create a LocalDate object from the "rescheduleFromDate" Date string
|
|
||||||
LocalDate localDate = jsonCommand.localDateValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.rescheduleFromDateParamName);
|
|
||||||
|
|
||||||
if(localDate != null) {
|
|
||||||
// get installment by due date
|
|
||||||
LoanRepaymentScheduleInstallment installment = loan.getRepaymentScheduleInstallment(localDate);
|
|
||||||
rescheduleFromInstallment = installment.getInstallmentNumber();
|
|
||||||
|
|
||||||
// update the value of the "rescheduleFromDate" variable
|
|
||||||
rescheduleFromDate = localDate.toDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(jsonCommand.hasParameter(RescheduleLoansApiConstants.adjustedDueDateParamName)) {
|
|
||||||
// create a LocalDate object from the "adjustedDueDate" Date string
|
|
||||||
LocalDate localDate = jsonCommand.localDateValueOfParameterNamed(
|
|
||||||
RescheduleLoansApiConstants.adjustedDueDateParamName);
|
|
||||||
|
|
||||||
if(localDate != null) {
|
|
||||||
// update the value of the "adjustedDueDate"variable
|
|
||||||
adjustedDueDate = localDate.toDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final LoanRescheduleRequest loanRescheduleRequest = LoanRescheduleRequest.instance(
|
|
||||||
loan, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(), rescheduleFromInstallment, graceOnPrincipal,
|
|
||||||
graceOnInterest, rescheduleFromDate, adjustedDueDate, extraTerms, recalculateInterest, interestRate, rescheduleReasonCodeValue,
|
|
||||||
rescheduleReasonComment, submittedOnDate, this.platformSecurityContext.authenticatedUser(),
|
|
||||||
null, null, null, null);
|
|
||||||
|
|
||||||
// create a new entry in the m_loan_reschedule_request table
|
|
||||||
this.loanRescheduleRequestRepository.save(loanRescheduleRequest);
|
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder()
|
|
||||||
.withCommandId(jsonCommand.commandId())
|
|
||||||
.withEntityId(loanRescheduleRequest.getId())
|
|
||||||
.withLoanId(loan.getId())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
catch(final DataIntegrityViolationException dve) {
|
|
||||||
// handle the data integrity violation
|
|
||||||
handleCreateActionDataIntegrityViolation(jsonCommand, dve);
|
|
||||||
|
|
||||||
// return an empty command processing result object
|
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public CommandProcessingResult approve(JsonCommand jsonCommand) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
final Long loanRescheduleRequestId = jsonCommand.entityId();
|
|
||||||
|
|
||||||
final LoanRescheduleRequest loanRescheduleRequest = this.loanRescheduleRequestRepository.findOne(loanRescheduleRequestId);
|
|
||||||
|
|
||||||
if(loanRescheduleRequest == null) {
|
|
||||||
throw new LoanRescheduleRequestNotFoundException(loanRescheduleRequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate the request in the JsonCommand object passed as parameter
|
|
||||||
this.loanRescheduleRequestDataValidator.validateForApproveAction(jsonCommand, loanRescheduleRequest);
|
|
||||||
|
|
||||||
final AppUser appUser = this.platformSecurityContext.authenticatedUser();
|
|
||||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
|
||||||
|
|
||||||
LocalDate approvedOnDate = jsonCommand.localDateValueOfParameterNamed("approvedOnDate");
|
|
||||||
final DateTimeFormatter dateTimeFormatter = DateTimeFormat
|
|
||||||
.forPattern(jsonCommand.dateFormat())
|
|
||||||
.withLocale(jsonCommand.extractLocale());
|
|
||||||
|
|
||||||
changes.put("locale", jsonCommand.locale());
|
|
||||||
changes.put("dateFormat", jsonCommand.dateFormat());
|
|
||||||
changes.put("approvedOnDate", approvedOnDate.toString(dateTimeFormatter));
|
|
||||||
changes.put("approvedByUserId", appUser.getId());
|
|
||||||
|
|
||||||
if(!changes.isEmpty()) {
|
|
||||||
Loan loan = loanRescheduleRequest.getLoan();
|
|
||||||
final LoanSummary loanSummary = loan.getSummary();
|
|
||||||
|
|
||||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
|
||||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
|
|
||||||
loan.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
|
||||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
|
||||||
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
|
||||||
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
|
||||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
|
||||||
|
|
||||||
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
|
||||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
|
||||||
final MathContext mathContext = new MathContext(8, roundingMode);
|
|
||||||
|
|
||||||
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
|
||||||
loanRescheduleRequest, applicationCurrency, isHolidayEnabled, holidays, workingDays);
|
|
||||||
|
|
||||||
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
|
|
||||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
|
||||||
|
|
||||||
for(LoanRescheduleModelRepaymentPeriod period : periods) {
|
|
||||||
|
|
||||||
if(period.isNew()) {
|
|
||||||
LoanRepaymentScheduleInstallment repaymentScheduleInstallment = new LoanRepaymentScheduleInstallment(
|
|
||||||
loan, period.periodNumber(), period.periodFromDate(), period.periodDueDate(), period.principalDue(),
|
|
||||||
period.interestDue(), BigDecimal.ZERO, BigDecimal.ZERO, false);
|
|
||||||
|
|
||||||
repaymentScheduleInstallments.add(repaymentScheduleInstallment);
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
for(LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
|
|
||||||
|
|
||||||
if(repaymentScheduleInstallment.getInstallmentNumber().equals(period.oldPeriodNumber())) {
|
|
||||||
|
|
||||||
repaymentScheduleInstallment.updateInstallmentNumber(period.periodNumber());
|
|
||||||
repaymentScheduleInstallment.updateFromDate(period.periodFromDate());
|
|
||||||
repaymentScheduleInstallment.updateDueDate(period.periodDueDate());
|
|
||||||
repaymentScheduleInstallment.updatePrincipal(period.principalDue());
|
|
||||||
repaymentScheduleInstallment.updateInterestCharged(period.interestDue());
|
|
||||||
|
|
||||||
if(Money.of(currency, period.principalDue()).isZero() &&
|
|
||||||
Money.of(currency, period.interestDue()).isZero() &&
|
|
||||||
repaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).isZero() &&
|
|
||||||
repaymentScheduleInstallment.getFeeChargesOutstanding(currency).isZero() &&
|
|
||||||
repaymentScheduleInstallment.isNotFullyPaidOff()) {
|
|
||||||
|
|
||||||
repaymentScheduleInstallment.updateObligationMet(true);
|
|
||||||
repaymentScheduleInstallment.updateObligationMetOnDate(new LocalDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = loanRescheduleModel.getOldPeriods();
|
|
||||||
|
|
||||||
for(LoanRepaymentScheduleHistory loanRepaymentScheduleHistory : loanRepaymentScheduleHistoryList) {
|
|
||||||
this.loanRepaymentScheduleHistoryRepository.save(loanRepaymentScheduleHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
loan.updateRescheduledByUser(appUser);
|
|
||||||
loan.updateRescheduledOnDate(new LocalDate());
|
|
||||||
|
|
||||||
// update the Loan summary
|
|
||||||
loanSummary.updateSummary(currency, loan.getPrincpal(), repaymentScheduleInstallments, new LoanSummaryWrapper(),
|
|
||||||
true);
|
|
||||||
|
|
||||||
// update the total number of schedule repayments
|
|
||||||
loan.updateNumberOfRepayments(periods.size());
|
|
||||||
|
|
||||||
// update the loan term frequency (loan term frequency = number of repayments)
|
|
||||||
loan.updateTermFrequency(periods.size());
|
|
||||||
|
|
||||||
// update the status of the request
|
|
||||||
loanRescheduleRequest.approve(appUser, approvedOnDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder()
|
|
||||||
.withCommandId(jsonCommand.commandId())
|
|
||||||
.withEntityId(loanRescheduleRequestId)
|
|
||||||
.withLoanId(loanRescheduleRequest.getLoan().getId())
|
|
||||||
.with(changes)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
catch(final DataIntegrityViolationException dve) {
|
|
||||||
// handle the data integrity violation
|
|
||||||
handleApproveActionDataIntegrityViolation(jsonCommand, dve);
|
|
||||||
|
|
||||||
// return an empty command processing result object
|
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||||
@Transactional
|
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
|
||||||
public CommandProcessingResult reject(JsonCommand jsonCommand) {
|
private final PlatformSecurityContext platformSecurityContext;
|
||||||
|
private final LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator;
|
||||||
try {
|
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
|
||||||
final Long loanRescheduleRequestId = jsonCommand.entityId();
|
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
||||||
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
final LoanRescheduleRequest loanRescheduleRequest = loanRescheduleRequestRepository
|
private final HolidayRepository holidayRepository;
|
||||||
.findOne(loanRescheduleRequestId);
|
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||||
|
private final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository;
|
||||||
if(loanRescheduleRequest == null) {
|
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
||||||
throw new LoanRescheduleRequestNotFoundException(loanRescheduleRequestId);
|
|
||||||
}
|
/**
|
||||||
|
* LoanRescheduleRequestWritePlatformServiceImpl constructor
|
||||||
// validate the request in the JsonCommand object passed as parameter
|
*
|
||||||
this.loanRescheduleRequestDataValidator.validateForRejectAction(jsonCommand, loanRescheduleRequest);
|
* @return void
|
||||||
|
**/
|
||||||
final AppUser appUser = this.platformSecurityContext.authenticatedUser();
|
@Autowired
|
||||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
public LoanRescheduleRequestWritePlatformServiceImpl(LoanRepositoryWrapper loanRepositoryWrapper,
|
||||||
|
CodeValueRepositoryWrapper codeValueRepositoryWrapper, PlatformSecurityContext platformSecurityContext,
|
||||||
LocalDate rejectedOnDate = jsonCommand.localDateValueOfParameterNamed("rejectedOnDate");
|
LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator,
|
||||||
final DateTimeFormatter dateTimeFormatter = DateTimeFormat
|
LoanRescheduleRequestRepository loanRescheduleRequestRepository,
|
||||||
.forPattern(jsonCommand.dateFormat())
|
ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, ConfigurationDomainService configurationDomainService,
|
||||||
.withLocale(jsonCommand.extractLocale());
|
HolidayRepository holidayRepository, WorkingDaysRepositoryWrapper workingDaysRepository,
|
||||||
|
LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository,
|
||||||
changes.put("locale", jsonCommand.locale());
|
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService) {
|
||||||
changes.put("dateFormat", jsonCommand.dateFormat());
|
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||||
changes.put("rejectedOnDate", rejectedOnDate.toString(dateTimeFormatter));
|
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
|
||||||
changes.put("rejectedByUserId", appUser.getId());
|
this.platformSecurityContext = platformSecurityContext;
|
||||||
|
this.loanRescheduleRequestDataValidator = loanRescheduleRequestDataValidator;
|
||||||
if(!changes.isEmpty()) {
|
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
||||||
loanRescheduleRequest.reject(appUser, rejectedOnDate);
|
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||||
}
|
this.configurationDomainService = configurationDomainService;
|
||||||
|
this.holidayRepository = holidayRepository;
|
||||||
return new CommandProcessingResultBuilder()
|
this.workingDaysRepository = workingDaysRepository;
|
||||||
.withCommandId(jsonCommand.commandId())
|
this.loanRepaymentScheduleHistoryRepository = loanRepaymentScheduleHistoryRepository;
|
||||||
.withEntityId(loanRescheduleRequestId)
|
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
|
||||||
.withLoanId(loanRescheduleRequest.getLoan().getId())
|
}
|
||||||
.with(changes)
|
|
||||||
.build();
|
/**
|
||||||
}
|
* create a new instance of the LoanRescheduleRequest object from the
|
||||||
|
* JsonCommand object and persist
|
||||||
catch(final DataIntegrityViolationException dve) {
|
*
|
||||||
// handle the data integrity violation
|
* @return CommandProcessingResult object
|
||||||
handleRejectActionDataIntegrityViolation(jsonCommand, dve);
|
**/
|
||||||
|
@Override
|
||||||
// return an empty command processing result object
|
@Transactional
|
||||||
return CommandProcessingResult.empty();
|
public CommandProcessingResult create(JsonCommand jsonCommand) {
|
||||||
}
|
|
||||||
}
|
try {
|
||||||
|
// get the loan id from the JsonCommand object
|
||||||
/**
|
final Long loanId = jsonCommand.longValueOfParameterNamed(RescheduleLoansApiConstants.loanIdParamName);
|
||||||
* handles the data integrity violation exception caught in the create method
|
|
||||||
*
|
// use the loan id to get a Loan entity object
|
||||||
* @param jsonCommand JSON command object
|
final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
|
||||||
* @param dve data integrity violation exception
|
|
||||||
* @return void
|
// validate the request in the JsonCommand object passed as
|
||||||
**/
|
// parameter
|
||||||
@SuppressWarnings("unused")
|
this.loanRescheduleRequestDataValidator.validateForCreateAction(jsonCommand, loan);
|
||||||
private void handleCreateActionDataIntegrityViolation(final JsonCommand jsonCommand,
|
|
||||||
final DataIntegrityViolationException dve) {
|
// get the reschedule reason code value id from the JsonCommand
|
||||||
|
// object
|
||||||
logger.error(dve.getMessage(), dve);
|
final Long rescheduleReasonId = jsonCommand.longValueOfParameterNamed(RescheduleLoansApiConstants.rescheduleReasonIdParamName);
|
||||||
|
|
||||||
throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue",
|
// use the reschedule reason code value id to get a CodeValue entity
|
||||||
|
// object
|
||||||
|
final CodeValue rescheduleReasonCodeValue = this.codeValueRepositoryWrapper.findOneWithNotFoundDetection(rescheduleReasonId);
|
||||||
|
|
||||||
|
// get the grace on principal integer value from the JsonCommand
|
||||||
|
// object
|
||||||
|
final Integer graceOnPrincipal = jsonCommand
|
||||||
|
.integerValueOfParameterNamed(RescheduleLoansApiConstants.graceOnPrincipalParamName);
|
||||||
|
|
||||||
|
// get the grace on interest integer value from the JsonCommand
|
||||||
|
// object
|
||||||
|
final Integer graceOnInterest = jsonCommand.integerValueOfParameterNamed(RescheduleLoansApiConstants.graceOnInterestParamName);
|
||||||
|
|
||||||
|
// get the extra terms to be added at the end of the new schedule
|
||||||
|
// from the JsonCommand object
|
||||||
|
final Integer extraTerms = jsonCommand.integerValueOfParameterNamed(RescheduleLoansApiConstants.extraTermsParamName);
|
||||||
|
|
||||||
|
// get the new interest rate that would be applied to the new loan
|
||||||
|
// schedule
|
||||||
|
final BigDecimal interestRate = jsonCommand
|
||||||
|
.bigDecimalValueOfParameterNamed(RescheduleLoansApiConstants.newInterestRateParamName);
|
||||||
|
|
||||||
|
// get the reschedule reason comment text from the JsonCommand
|
||||||
|
// object
|
||||||
|
final String rescheduleReasonComment = jsonCommand
|
||||||
|
.stringValueOfParameterNamed(RescheduleLoansApiConstants.rescheduleReasonCommentParamName);
|
||||||
|
|
||||||
|
// get the recalculate interest option
|
||||||
|
final Boolean recalculateInterest = jsonCommand
|
||||||
|
.booleanObjectValueOfParameterNamed(RescheduleLoansApiConstants.recalculateInterestParamName);
|
||||||
|
|
||||||
|
// initialize set the value to null
|
||||||
|
Date submittedOnDate = null;
|
||||||
|
|
||||||
|
// check if the parameter is in the JsonCommand object
|
||||||
|
if (jsonCommand.hasParameter(RescheduleLoansApiConstants.submittedOnDateParamName)) {
|
||||||
|
// create a LocalDate object from the "submittedOnDate" Date
|
||||||
|
// string
|
||||||
|
LocalDate localDate = jsonCommand.localDateValueOfParameterNamed(RescheduleLoansApiConstants.submittedOnDateParamName);
|
||||||
|
|
||||||
|
if (localDate != null) {
|
||||||
|
// update the value of the "submittedOnDate" variable
|
||||||
|
submittedOnDate = localDate.toDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initially set the value to null
|
||||||
|
Date rescheduleFromDate = null;
|
||||||
|
|
||||||
|
// start point of the rescheduling exercise
|
||||||
|
Integer rescheduleFromInstallment = null;
|
||||||
|
|
||||||
|
// initially set the value to null
|
||||||
|
Date adjustedDueDate = null;
|
||||||
|
|
||||||
|
// check if the parameter is in the JsonCommand object
|
||||||
|
if (jsonCommand.hasParameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)) {
|
||||||
|
// create a LocalDate object from the "rescheduleFromDate" Date
|
||||||
|
// string
|
||||||
|
LocalDate localDate = jsonCommand.localDateValueOfParameterNamed(RescheduleLoansApiConstants.rescheduleFromDateParamName);
|
||||||
|
|
||||||
|
if (localDate != null) {
|
||||||
|
// get installment by due date
|
||||||
|
LoanRepaymentScheduleInstallment installment = loan.getRepaymentScheduleInstallment(localDate);
|
||||||
|
rescheduleFromInstallment = installment.getInstallmentNumber();
|
||||||
|
|
||||||
|
// update the value of the "rescheduleFromDate" variable
|
||||||
|
rescheduleFromDate = localDate.toDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonCommand.hasParameter(RescheduleLoansApiConstants.adjustedDueDateParamName)) {
|
||||||
|
// create a LocalDate object from the "adjustedDueDate" Date
|
||||||
|
// string
|
||||||
|
LocalDate localDate = jsonCommand.localDateValueOfParameterNamed(RescheduleLoansApiConstants.adjustedDueDateParamName);
|
||||||
|
|
||||||
|
if (localDate != null) {
|
||||||
|
// update the value of the "adjustedDueDate"variable
|
||||||
|
adjustedDueDate = localDate.toDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final LoanRescheduleRequest loanRescheduleRequest = LoanRescheduleRequest.instance(loan,
|
||||||
|
LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(), rescheduleFromInstallment, graceOnPrincipal, graceOnInterest,
|
||||||
|
rescheduleFromDate, adjustedDueDate, extraTerms, recalculateInterest, interestRate, rescheduleReasonCodeValue,
|
||||||
|
rescheduleReasonComment, submittedOnDate, this.platformSecurityContext.authenticatedUser(), null, null, null, null);
|
||||||
|
|
||||||
|
// create a new entry in the m_loan_reschedule_request table
|
||||||
|
this.loanRescheduleRequestRepository.save(loanRescheduleRequest);
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(loanRescheduleRequest.getId())
|
||||||
|
.withLoanId(loan.getId()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (final DataIntegrityViolationException dve) {
|
||||||
|
// handle the data integrity violation
|
||||||
|
handleCreateActionDataIntegrityViolation(jsonCommand, dve);
|
||||||
|
|
||||||
|
// return an empty command processing result object
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public CommandProcessingResult approve(JsonCommand jsonCommand) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Long loanRescheduleRequestId = jsonCommand.entityId();
|
||||||
|
|
||||||
|
final LoanRescheduleRequest loanRescheduleRequest = this.loanRescheduleRequestRepository.findOne(loanRescheduleRequestId);
|
||||||
|
|
||||||
|
if (loanRescheduleRequest == null) { throw new LoanRescheduleRequestNotFoundException(loanRescheduleRequestId); }
|
||||||
|
|
||||||
|
// validate the request in the JsonCommand object passed as
|
||||||
|
// parameter
|
||||||
|
this.loanRescheduleRequestDataValidator.validateForApproveAction(jsonCommand, loanRescheduleRequest);
|
||||||
|
|
||||||
|
final AppUser appUser = this.platformSecurityContext.authenticatedUser();
|
||||||
|
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
|
LocalDate approvedOnDate = jsonCommand.localDateValueOfParameterNamed("approvedOnDate");
|
||||||
|
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(
|
||||||
|
jsonCommand.extractLocale());
|
||||||
|
|
||||||
|
changes.put("locale", jsonCommand.locale());
|
||||||
|
changes.put("dateFormat", jsonCommand.dateFormat());
|
||||||
|
changes.put("approvedOnDate", approvedOnDate.toString(dateTimeFormatter));
|
||||||
|
changes.put("approvedByUserId", appUser.getId());
|
||||||
|
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
Loan loan = loanRescheduleRequest.getLoan();
|
||||||
|
final LoanSummary loanSummary = loan.getSummary();
|
||||||
|
|
||||||
|
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
|
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
|
||||||
|
.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
||||||
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
||||||
|
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
||||||
|
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||||
|
|
||||||
|
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
||||||
|
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||||
|
final MathContext mathContext = new MathContext(8, roundingMode);
|
||||||
|
|
||||||
|
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = this.loanScheduleHistoryWritePlatformService
|
||||||
|
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
||||||
|
|
||||||
|
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
||||||
|
loanRescheduleRequest, applicationCurrency, isHolidayEnabled, holidays, workingDays);
|
||||||
|
|
||||||
|
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
|
||||||
|
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||||
|
|
||||||
|
for (LoanRescheduleModelRepaymentPeriod period : periods) {
|
||||||
|
|
||||||
|
if (period.isNew()) {
|
||||||
|
LoanRepaymentScheduleInstallment repaymentScheduleInstallment = new LoanRepaymentScheduleInstallment(loan,
|
||||||
|
period.periodNumber(), period.periodFromDate(), period.periodDueDate(), period.principalDue(),
|
||||||
|
period.interestDue(), BigDecimal.ZERO, BigDecimal.ZERO, false);
|
||||||
|
|
||||||
|
repaymentScheduleInstallments.add(repaymentScheduleInstallment);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
for (LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
|
||||||
|
|
||||||
|
if (repaymentScheduleInstallment.getInstallmentNumber().equals(period.oldPeriodNumber())) {
|
||||||
|
|
||||||
|
repaymentScheduleInstallment.updateInstallmentNumber(period.periodNumber());
|
||||||
|
repaymentScheduleInstallment.updateFromDate(period.periodFromDate());
|
||||||
|
repaymentScheduleInstallment.updateDueDate(period.periodDueDate());
|
||||||
|
repaymentScheduleInstallment.updatePrincipal(period.principalDue());
|
||||||
|
repaymentScheduleInstallment.updateInterestCharged(period.interestDue());
|
||||||
|
|
||||||
|
if (Money.of(currency, period.principalDue()).isZero() && Money.of(currency, period.interestDue()).isZero()
|
||||||
|
&& repaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).isZero()
|
||||||
|
&& repaymentScheduleInstallment.getFeeChargesOutstanding(currency).isZero()
|
||||||
|
&& repaymentScheduleInstallment.isNotFullyPaidOff()) {
|
||||||
|
|
||||||
|
repaymentScheduleInstallment.updateObligationMet(true);
|
||||||
|
repaymentScheduleInstallment.updateObligationMetOnDate(new LocalDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (LoanRepaymentScheduleHistory loanRepaymentScheduleHistory : loanRepaymentScheduleHistoryList) {
|
||||||
|
this.loanRepaymentScheduleHistoryRepository.save(loanRepaymentScheduleHistory);
|
||||||
|
}
|
||||||
|
|
||||||
|
loan.updateRescheduledByUser(appUser);
|
||||||
|
loan.updateRescheduledOnDate(new LocalDate());
|
||||||
|
|
||||||
|
// update the Loan summary
|
||||||
|
loanSummary.updateSummary(currency, loan.getPrincpal(), repaymentScheduleInstallments, new LoanSummaryWrapper(), true);
|
||||||
|
|
||||||
|
// update the total number of schedule repayments
|
||||||
|
loan.updateNumberOfRepayments(periods.size());
|
||||||
|
|
||||||
|
// update the loan term frequency (loan term frequency = number
|
||||||
|
// of repayments)
|
||||||
|
loan.updateTermFrequency(periods.size());
|
||||||
|
|
||||||
|
// update the status of the request
|
||||||
|
loanRescheduleRequest.approve(appUser, approvedOnDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(loanRescheduleRequestId)
|
||||||
|
.withLoanId(loanRescheduleRequest.getLoan().getId()).with(changes).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (final DataIntegrityViolationException dve) {
|
||||||
|
// handle the data integrity violation
|
||||||
|
handleApproveActionDataIntegrityViolation(jsonCommand, dve);
|
||||||
|
|
||||||
|
// return an empty command processing result object
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public CommandProcessingResult reject(JsonCommand jsonCommand) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Long loanRescheduleRequestId = jsonCommand.entityId();
|
||||||
|
|
||||||
|
final LoanRescheduleRequest loanRescheduleRequest = loanRescheduleRequestRepository.findOne(loanRescheduleRequestId);
|
||||||
|
|
||||||
|
if (loanRescheduleRequest == null) { throw new LoanRescheduleRequestNotFoundException(loanRescheduleRequestId); }
|
||||||
|
|
||||||
|
// validate the request in the JsonCommand object passed as
|
||||||
|
// parameter
|
||||||
|
this.loanRescheduleRequestDataValidator.validateForRejectAction(jsonCommand, loanRescheduleRequest);
|
||||||
|
|
||||||
|
final AppUser appUser = this.platformSecurityContext.authenticatedUser();
|
||||||
|
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
|
LocalDate rejectedOnDate = jsonCommand.localDateValueOfParameterNamed("rejectedOnDate");
|
||||||
|
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(
|
||||||
|
jsonCommand.extractLocale());
|
||||||
|
|
||||||
|
changes.put("locale", jsonCommand.locale());
|
||||||
|
changes.put("dateFormat", jsonCommand.dateFormat());
|
||||||
|
changes.put("rejectedOnDate", rejectedOnDate.toString(dateTimeFormatter));
|
||||||
|
changes.put("rejectedByUserId", appUser.getId());
|
||||||
|
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
loanRescheduleRequest.reject(appUser, rejectedOnDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(loanRescheduleRequestId)
|
||||||
|
.withLoanId(loanRescheduleRequest.getLoan().getId()).with(changes).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (final DataIntegrityViolationException dve) {
|
||||||
|
// handle the data integrity violation
|
||||||
|
handleRejectActionDataIntegrityViolation(jsonCommand, dve);
|
||||||
|
|
||||||
|
// return an empty command processing result object
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handles the data integrity violation exception caught in the create
|
||||||
|
* method
|
||||||
|
*
|
||||||
|
* @param jsonCommand
|
||||||
|
* JSON command object
|
||||||
|
* @param dve
|
||||||
|
* data integrity violation exception
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void handleCreateActionDataIntegrityViolation(final JsonCommand jsonCommand, final DataIntegrityViolationException dve) {
|
||||||
|
|
||||||
|
logger.error(dve.getMessage(), dve);
|
||||||
|
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue",
|
||||||
"Unknown data integrity issue with resource.");
|
"Unknown data integrity issue with resource.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handles the data integrity violation exception caught in the reject method
|
* handles the data integrity violation exception caught in the reject
|
||||||
*
|
* method
|
||||||
* @param jsonCommand JSON command object
|
*
|
||||||
* @param dve data integrity violation exception
|
* @param jsonCommand
|
||||||
* @return void
|
* JSON command object
|
||||||
**/
|
* @param dve
|
||||||
@SuppressWarnings("unused")
|
* data integrity violation exception
|
||||||
private void handleRejectActionDataIntegrityViolation(final JsonCommand jsonCommand,
|
* @return void
|
||||||
final DataIntegrityViolationException dve) {
|
**/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
logger.error(dve.getMessage(), dve);
|
private void handleRejectActionDataIntegrityViolation(final JsonCommand jsonCommand, final DataIntegrityViolationException dve) {
|
||||||
|
|
||||||
throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue",
|
logger.error(dve.getMessage(), dve);
|
||||||
|
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue",
|
||||||
"Unknown data integrity issue with resource.");
|
"Unknown data integrity issue with resource.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handles the data integrity violation exception caught in the approve method
|
* handles the data integrity violation exception caught in the approve
|
||||||
*
|
* method
|
||||||
* @param jsonCommand JSON command object
|
*
|
||||||
* @param dve data integrity violation exception
|
* @param jsonCommand
|
||||||
* @return void
|
* JSON command object
|
||||||
**/
|
* @param dve
|
||||||
@SuppressWarnings("unused")
|
* data integrity violation exception
|
||||||
private void handleApproveActionDataIntegrityViolation(final JsonCommand jsonCommand,
|
* @return void
|
||||||
final DataIntegrityViolationException dve) {
|
**/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
logger.error(dve.getMessage(), dve);
|
private void handleApproveActionDataIntegrityViolation(final JsonCommand jsonCommand, final DataIntegrityViolationException dve) {
|
||||||
|
|
||||||
throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue",
|
logger.error(dve.getMessage(), dve);
|
||||||
|
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue",
|
||||||
"Unknown data integrity issue with resource.");
|
"Unknown data integrity issue with resource.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+93
-6
@@ -111,7 +111,10 @@ import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFound
|
|||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator;
|
import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator;
|
||||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
|
import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||||
@@ -168,6 +171,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final AccountTransferRepository accountTransferRepository;
|
private final AccountTransferRepository accountTransferRepository;
|
||||||
private final CalendarRepository calendarRepository;
|
private final CalendarRepository calendarRepository;
|
||||||
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
|
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
|
||||||
|
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -188,7 +192,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final LoanChargeReadPlatformService loanChargeReadPlatformService, final LoanReadPlatformService loanReadPlatformService,
|
final LoanChargeReadPlatformService loanChargeReadPlatformService, final LoanReadPlatformService loanReadPlatformService,
|
||||||
final FromJsonHelper fromApiJsonHelper, final AccountTransferRepository accountTransferRepository,
|
final FromJsonHelper fromApiJsonHelper, final AccountTransferRepository accountTransferRepository,
|
||||||
final CalendarRepository calendarRepository,
|
final CalendarRepository calendarRepository,
|
||||||
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository) {
|
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
|
||||||
|
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||||
this.loanAssembler = loanAssembler;
|
this.loanAssembler = loanAssembler;
|
||||||
@@ -217,6 +222,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.accountTransferRepository = accountTransferRepository;
|
this.accountTransferRepository = accountTransferRepository;
|
||||||
this.calendarRepository = calendarRepository;
|
this.calendarRepository = calendarRepository;
|
||||||
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
|
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
|
||||||
|
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||||
@@ -316,7 +322,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
createLoanScheduleArchive(loan, applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
|
}
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -510,6 +519,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
createLoanScheduleArchive(loan, applicationCurrency, firstRepaymentOnDate, isHolidayEnabled, holidays, workingDays);
|
||||||
|
}
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
}
|
}
|
||||||
final Set<LoanCharge> loanCharges = loan.charges();
|
final Set<LoanCharge> loanCharges = loan.charges();
|
||||||
@@ -1130,9 +1142,31 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||||
this.loanChargeRepository.save(loanCharge);
|
this.loanChargeRepository.save(loanCharge);
|
||||||
|
CalendarInstance restCalendarInstance = null;
|
||||||
|
ApplicationCurrency applicationCurrency = null;
|
||||||
|
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||||
|
List<Holiday> holidays = null;
|
||||||
|
boolean isHolidayEnabled = false;
|
||||||
|
WorkingDays workingDays = null;
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||||
|
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
|
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||||
|
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||||
|
CalendarEntityType.LOANS.getValue());
|
||||||
|
calculatedRepaymentsStartingFromDate = this.loanAccountDomainService.getCalculatedRepaymentsStartingFromDate(
|
||||||
|
loan.getDisbursementDate(), loan, calendarInstance);
|
||||||
|
|
||||||
|
isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
|
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
||||||
|
workingDays = this.workingDaysRepository.findOne();
|
||||||
|
}
|
||||||
|
|
||||||
final ChangedTransactionDetail changedTransactionDetail = loan.addLoanCharge(loanCharge, existingTransactionIds,
|
final ChangedTransactionDetail changedTransactionDetail = loan.addLoanCharge(loanCharge, existingTransactionIds,
|
||||||
existingReversedTransactionIds);
|
existingReversedTransactionIds, holidays, workingDays, isHolidayEnabled, loanScheduleFactory, applicationCurrency,
|
||||||
|
calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we want to apply charge transactions only for those loans charges
|
* we want to apply charge transactions only for those loans charges
|
||||||
@@ -1161,7 +1195,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
createLoanScheduleArchive(loan, applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
|
}
|
||||||
// we post Journal entries only for loans in active status
|
// we post Journal entries only for loans in active status
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
}
|
}
|
||||||
@@ -1246,9 +1283,31 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||||
|
CalendarInstance restCalendarInstance = null;
|
||||||
|
ApplicationCurrency applicationCurrency = null;
|
||||||
|
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||||
|
List<Holiday> holidays = null;
|
||||||
|
boolean isHolidayEnabled = false;
|
||||||
|
WorkingDays workingDays = null;
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||||
|
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
|
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||||
|
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||||
|
CalendarEntityType.LOANS.getValue());
|
||||||
|
calculatedRepaymentsStartingFromDate = this.loanAccountDomainService.getCalculatedRepaymentsStartingFromDate(
|
||||||
|
loan.getDisbursementDate(), loan, calendarInstance);
|
||||||
|
|
||||||
|
isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
|
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
||||||
|
workingDays = this.workingDaysRepository.findOne();
|
||||||
|
}
|
||||||
|
|
||||||
final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes,
|
final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes,
|
||||||
existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber);
|
existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber, holidays, workingDays, isHolidayEnabled,
|
||||||
|
loanScheduleFactory, applicationCurrency, calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||||
|
|
||||||
this.loanTransactionRepository.save(waiveTransaction);
|
this.loanTransactionRepository.save(waiveTransaction);
|
||||||
saveLoanWithDataIntegrityViolationChecks(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
@@ -2103,7 +2162,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
createLoanScheduleArchive(loan, applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
|
}
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
this.loanAccountDomainService.recalculateAccruals(loan);
|
this.loanAccountDomainService.recalculateAccruals(loan);
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
@@ -2243,4 +2305,29 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createLoanScheduleArchive(final Loan loan, final ApplicationCurrency applicationCurrency,
|
||||||
|
final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled, final List<Holiday> holidays,
|
||||||
|
final WorkingDays workingDays) {
|
||||||
|
LoanScheduleModel loanScheduleModel = loan.regenerateScheduleModel(loanScheduleFactory, applicationCurrency,
|
||||||
|
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays);
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments = retrieveRepaymentScheduleFromModel(loanScheduleModel);
|
||||||
|
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(installments, loan, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||||
|
for (final LoanScheduleModelPeriod scheduledLoanInstallment : model.getPeriods()) {
|
||||||
|
if (scheduledLoanInstallment.isRepaymentPeriod()) {
|
||||||
|
final LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(null,
|
||||||
|
scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
|
||||||
|
scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
|
||||||
|
scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
|
||||||
|
scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent());
|
||||||
|
installments.add(installment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return installments;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user