MIFOSX-175: WIP - adding loan summary fields to loan table and resultant refactor of loan schedule and loan summary retrieval code.
This commit is contained in:
@@ -540,7 +540,6 @@ CREATE TABLE `m_loan` (
|
||||
`repay_every` smallint(5) NOT NULL,
|
||||
`repayment_period_frequency_enum` smallint(5) NOT NULL,
|
||||
`amortization_method_enum` smallint(5) NOT NULL,
|
||||
`total_charges_due_at_disbursement_derived` decimal(19,6) DEFAULT NULL,
|
||||
`interest_calculated_from_date` date DEFAULT NULL,
|
||||
`expected_disbursedon_date` date DEFAULT NULL,
|
||||
`expected_firstrepaymenton_date` date DEFAULT NULL,
|
||||
@@ -560,6 +559,30 @@ CREATE TABLE `m_loan` (
|
||||
`writtenoffon_date` date DEFAULT NULL,
|
||||
`closedon_date` date DEFAULT NULL,
|
||||
`closedon_userid` bigint(20) DEFAULT NULL,
|
||||
`total_charges_due_at_disbursement_derived` decimal(19,6) DEFAULT NULL,
|
||||
`principal_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`principal_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`interest_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`interest_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`interest_waived_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`interest_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`fee_charges_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`fee_charges_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`fee_charges_waived_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`fee_charges_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`penalty_charges_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`penalty_charges_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`penalty_charges_waived_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`penalty_charges_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`principal_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`interest_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`fee_charges_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`penalty_charges_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`principal_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`interest_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`fee_charges_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`penalty_charges_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0,
|
||||
`first_overdue_installment_date_derived` DATE NULL,
|
||||
`createdby_id` bigint(20) DEFAULT NULL,
|
||||
`created_date` datetime DEFAULT NULL,
|
||||
`lastmodified_date` datetime DEFAULT NULL,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,43 @@
|
||||
ALTER TABLE `m_loan`
|
||||
DROP COLUMN `lastmodifiedby_id`,
|
||||
DROP COLUMN `lastmodified_date`,
|
||||
DROP COLUMN `created_date`,
|
||||
DROP COLUMN `createdby_id`;
|
||||
|
||||
|
||||
ALTER TABLE `m_loan`
|
||||
CHANGE COLUMN `total_charges_due_at_disbursement_derived` `total_charges_due_at_disbursement_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `closedon_userid` ;
|
||||
|
||||
ALTER TABLE `m_loan`
|
||||
ADD COLUMN `principal_disbursed_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_charges_due_at_disbursement_derived` ,
|
||||
ADD COLUMN `principal_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `principal_disbursed_derived` ,
|
||||
ADD COLUMN `principal_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `principal_repaid_derived` ,
|
||||
ADD COLUMN `principal_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `principal_writtenoff_derived`,
|
||||
ADD COLUMN `principal_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `principal_outstanding_derived`,
|
||||
ADD COLUMN `interest_charged_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `principal_overdue_derived` ,
|
||||
ADD COLUMN `interest_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `interest_charged_derived` ,
|
||||
ADD COLUMN `interest_waived_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `interest_repaid_derived` ,
|
||||
ADD COLUMN `interest_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `interest_waived_derived` ,
|
||||
ADD COLUMN `interest_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `interest_writtenoff_derived`,
|
||||
ADD COLUMN `interest_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `interest_outstanding_derived`,
|
||||
ADD COLUMN `fee_charges_charged_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `interest_overdue_derived` ,
|
||||
ADD COLUMN `fee_charges_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `fee_charges_charged_derived` ,
|
||||
ADD COLUMN `fee_charges_waived_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `fee_charges_repaid_derived` ,
|
||||
ADD COLUMN `fee_charges_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `fee_charges_waived_derived` ,
|
||||
ADD COLUMN `fee_charges_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `fee_charges_writtenoff_derived`,
|
||||
ADD COLUMN `fee_charges_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `fee_charges_outstanding_derived`,
|
||||
ADD COLUMN `penalty_charges_charged_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `fee_charges_overdue_derived` ,
|
||||
ADD COLUMN `penalty_charges_repaid_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `penalty_charges_charged_derived` ,
|
||||
ADD COLUMN `penalty_charges_waived_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `penalty_charges_repaid_derived` ,
|
||||
ADD COLUMN `penalty_charges_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `penalty_charges_waived_derived`,
|
||||
ADD COLUMN `penalty_charges_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `penalty_charges_writtenoff_derived`,
|
||||
ADD COLUMN `penalty_charges_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `penalty_charges_outstanding_derived`,
|
||||
ADD COLUMN `total_expected_repayment_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `penalty_charges_overdue_derived`,
|
||||
ADD COLUMN `total_repayment_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_expected_repayment_derived`,
|
||||
ADD COLUMN `total_expected_costofloan_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_repayment_derived`,
|
||||
ADD COLUMN `total_costofloan_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_expected_costofloan_derived`,
|
||||
ADD COLUMN `total_waived_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_costofloan_derived`,
|
||||
ADD COLUMN `total_writtenoff_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_waived_derived`,
|
||||
ADD COLUMN `total_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_writtenoff_derived`,
|
||||
ADD COLUMN `total_overdue_derived` DECIMAL(19,6) NOT NULL DEFAULT 0.0 AFTER `total_outstanding_derived`,
|
||||
ADD COLUMN `overdue_since_date_derived` DATE NULL AFTER `total_outstanding_derived`;
|
||||
+50
-36
@@ -16,46 +16,60 @@ import org.joda.time.LocalDate;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
/**
|
||||
* Support for retrieving possibly null values from jdbc recordset delegating to springs {@link JdbcUtils} where possible.
|
||||
* Support for retrieving possibly null values from jdbc recordset delegating to
|
||||
* springs {@link JdbcUtils} where possible.
|
||||
*/
|
||||
public class JdbcSupport {
|
||||
|
||||
public static DateTime getDateTime(ResultSet rs, String columnName) throws SQLException {
|
||||
DateTime dateTime = null;
|
||||
Timestamp dateValue = rs.getTimestamp(columnName);
|
||||
if (dateValue != null) {
|
||||
dateTime = new DateTime(dateValue.getTime());
|
||||
}
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
public static LocalDate getLocalDate(final ResultSet rs, final String columnName) throws SQLException {
|
||||
LocalDate localDate = null;
|
||||
Date dateValue = rs.getDate(columnName);
|
||||
if (dateValue != null) {
|
||||
localDate = new LocalDate(dateValue);
|
||||
}
|
||||
return localDate;
|
||||
}
|
||||
public static DateTime getDateTime(final ResultSet rs, final String columnName) throws SQLException {
|
||||
DateTime dateTime = null;
|
||||
Timestamp dateValue = rs.getTimestamp(columnName);
|
||||
if (dateValue != null) {
|
||||
dateTime = new DateTime(dateValue.getTime());
|
||||
}
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
public static Long getLong(final ResultSet rs, final String columnName) throws SQLException {
|
||||
return (Long) JdbcUtils.getResultSetValue(rs, rs.findColumn(columnName), Long.class);
|
||||
}
|
||||
public static LocalDate getLocalDate(final ResultSet rs, final String columnName) throws SQLException {
|
||||
LocalDate localDate = null;
|
||||
final Date dateValue = rs.getDate(columnName);
|
||||
if (dateValue != null) {
|
||||
localDate = new LocalDate(dateValue);
|
||||
}
|
||||
return localDate;
|
||||
}
|
||||
|
||||
public static Integer getInteger(final ResultSet rs, final String columnName) throws SQLException {
|
||||
return (Integer) JdbcUtils.getResultSetValue(rs, rs.findColumn(columnName), Integer.class);
|
||||
}
|
||||
public static Long getLong(final ResultSet rs, final String columnName) throws SQLException {
|
||||
return (Long) JdbcUtils.getResultSetValue(rs, rs.findColumn(columnName), Long.class);
|
||||
}
|
||||
|
||||
public static BigDecimal getBigDecimalDefaultToZeroIfNull(final ResultSet rs, final String columnName) throws SQLException {
|
||||
final BigDecimal value = rs.getBigDecimal(columnName);
|
||||
return defaultToZeroIfNull(value);
|
||||
}
|
||||
|
||||
private static BigDecimal defaultToZeroIfNull(final BigDecimal value) {
|
||||
BigDecimal result = BigDecimal.ZERO;
|
||||
if (value != null) {
|
||||
result = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static Integer getInteger(final ResultSet rs, final String columnName) throws SQLException {
|
||||
return (Integer) JdbcUtils.getResultSetValue(rs, rs.findColumn(columnName), Integer.class);
|
||||
}
|
||||
|
||||
public static BigDecimal getBigDecimalDefaultToZeroIfNull(final ResultSet rs, final String columnName) throws SQLException {
|
||||
final BigDecimal value = rs.getBigDecimal(columnName);
|
||||
return defaultToZeroIfNull(value);
|
||||
}
|
||||
|
||||
private static BigDecimal defaultToZeroIfNull(final BigDecimal value) {
|
||||
BigDecimal result = BigDecimal.ZERO;
|
||||
if (value != null) {
|
||||
result = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static BigDecimal getBigDecimalDefaultToNullIfZero(final ResultSet rs, final String columnName) throws SQLException {
|
||||
final BigDecimal value = rs.getBigDecimal(columnName);
|
||||
return defaultToNullIfZero(value);
|
||||
}
|
||||
|
||||
private static BigDecimal defaultToNullIfZero(final BigDecimal value) {
|
||||
BigDecimal result = value;
|
||||
if (BigDecimal.ZERO.compareTo(value) == 0) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -81,9 +81,9 @@ public class LoansApiResource {
|
||||
"inArrearsTolerance", "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery",
|
||||
"interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId",
|
||||
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
|
||||
"expectedFirstRepaymentOnDate", "interestChargedFromDate", "timeline", "totalFeeChargesAtDisbursement", "repaymentSchedule",
|
||||
"transactions", "charges", "collateral", "guarantors", "productOptions", "amortizationTypeOptions", "interestTypeOptions",
|
||||
"interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "termFrequencyTypeOptions",
|
||||
"expectedFirstRepaymentOnDate", "interestChargedFromDate", "timeline", "totalFeeChargesAtDisbursement", "summary",
|
||||
"repaymentSchedule", "transactions", "charges", "collateral", "guarantors", "productOptions", "amortizationTypeOptions",
|
||||
"interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "termFrequencyTypeOptions",
|
||||
"interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "loanOfficerOptions",
|
||||
"loanPurposeOptions", "loanCollateralOptions", "chargeTemplate"));
|
||||
|
||||
@@ -146,7 +146,7 @@ public class LoansApiResource {
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String templateForNewLoanApplication(@QueryParam("clientId") final Long clientId, @QueryParam("groupId") final Long groupId,
|
||||
public String template(@QueryParam("clientId") final Long clientId, @QueryParam("groupId") final Long groupId,
|
||||
@QueryParam("productId") final Long productId, @Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
@@ -217,7 +217,7 @@ public class LoansApiResource {
|
||||
@Path("{loanId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveLoanAccountDetails(@PathParam("loanId") final Long loanId, @Context final UriInfo uriInfo) {
|
||||
public String retrieveLoan(@PathParam("loanId") final Long loanId, @Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
|
||||
|
||||
+50
-39
@@ -9,6 +9,8 @@ import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
@@ -69,7 +71,7 @@ public class LoanAccountData {
|
||||
// timeline
|
||||
private final LoanApplicationTimelineData timeline;
|
||||
// totals
|
||||
private final BigDecimal totalFeeChargesAtDisbursement;
|
||||
private final LoanSummaryData summary;
|
||||
|
||||
// associations
|
||||
private final LoanScheduleData repaymentSchedule;
|
||||
@@ -95,6 +97,9 @@ public class LoanAccountData {
|
||||
|
||||
private final ChargeData chargeTemplate;
|
||||
|
||||
@Transient
|
||||
private BigDecimal feeChargesAtDisbursementCharged;
|
||||
|
||||
/**
|
||||
* Used to produce a {@link LoanAccountData} with only collateral options
|
||||
* for now.
|
||||
@@ -137,7 +142,8 @@ public class LoanAccountData {
|
||||
final LocalDate expectedFirstRepaymentOnDate = null;
|
||||
final LocalDate interestChargedFromDate = null;
|
||||
final LoanApplicationTimelineData timeline = null;
|
||||
final BigDecimal totalFeeChargesAtDisbursement = null;
|
||||
final LoanSummaryData summary = null;
|
||||
final BigDecimal feeChargesDueAtDisbursementCharged = null;
|
||||
|
||||
final LoanScheduleData repaymentSchedule = null;
|
||||
final Collection<LoanTransactionData> transactions = null;
|
||||
@@ -163,11 +169,11 @@ public class LoanAccountData {
|
||||
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
|
||||
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionProcessingStrategyId, amortizationType,
|
||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
|
||||
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule,
|
||||
transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
|
||||
loanCollateralOptions);
|
||||
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged,
|
||||
repaymentSchedule, transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions,
|
||||
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions,
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
||||
loanPurposeOptions, loanCollateralOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,7 +216,8 @@ public class LoanAccountData {
|
||||
final LocalDate expectedFirstRepaymentOnDate = null;
|
||||
final LocalDate interestChargedFromDate = null;
|
||||
final LoanApplicationTimelineData timeline = LoanApplicationTimelineData.templateDefault(expectedDisbursementDate);
|
||||
final BigDecimal totalFeeChargesAtDisbursement = null;
|
||||
final LoanSummaryData summary = null;
|
||||
final BigDecimal feeChargesDueAtDisbursementCharged = null;
|
||||
|
||||
final LoanScheduleData repaymentSchedule = null;
|
||||
final Collection<LoanTransactionData> transactions = null;
|
||||
@@ -237,11 +244,11 @@ public class LoanAccountData {
|
||||
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
|
||||
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionProcessingStrategyId, amortizationType,
|
||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
|
||||
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule,
|
||||
transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
|
||||
loanCollateralOptions);
|
||||
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged,
|
||||
repaymentSchedule, transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions,
|
||||
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions,
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
||||
loanPurposeOptions, loanCollateralOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +292,8 @@ public class LoanAccountData {
|
||||
final LocalDate expectedFirstRepaymentOnDate = null;
|
||||
final LocalDate interestChargedFromDate = null;
|
||||
final LoanApplicationTimelineData timeline = LoanApplicationTimelineData.templateDefault(expectedDisbursementDate);
|
||||
final BigDecimal totalFeeChargesAtDisbursement = null;
|
||||
final LoanSummaryData summary = null;
|
||||
final BigDecimal feeChargesDueAtDisbursementCharged = null;
|
||||
|
||||
final LoanScheduleData repaymentSchedule = null;
|
||||
final Collection<LoanTransactionData> transactions = null;
|
||||
@@ -312,11 +320,11 @@ public class LoanAccountData {
|
||||
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
|
||||
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionProcessingStrategyId, amortizationType,
|
||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
|
||||
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule,
|
||||
transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
|
||||
loanCollateralOptions);
|
||||
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged,
|
||||
repaymentSchedule, transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions,
|
||||
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions,
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
||||
loanPurposeOptions, loanCollateralOptions);
|
||||
}
|
||||
|
||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||
@@ -357,10 +365,10 @@ public class LoanAccountData {
|
||||
product.getTransactionProcessingStrategyId(), product.getAmortizationType(), product.getInterestRatePerPeriod(),
|
||||
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(),
|
||||
product.getInterestCalculationPeriodType(), acc.expectedFirstRepaymentOnDate, acc.interestChargedFromDate, acc.timeline,
|
||||
acc.totalFeeChargesAtDisbursement, repaymentSchedule, transactions, charges, collateral, guarantors, productOptions,
|
||||
termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions,
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
|
||||
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
|
||||
acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors,
|
||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -378,7 +386,8 @@ public class LoanAccountData {
|
||||
final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType, final BigDecimal annualInterestRate,
|
||||
final EnumOptionData interestType, final EnumOptionData interestCalculationPeriodType,
|
||||
final LocalDate expectedFirstRepaymentOnDate, final LocalDate interestChargedFromDate,
|
||||
final LoanApplicationTimelineData timeline, final BigDecimal totalFeeChargesAtDisbursement) {
|
||||
final LoanApplicationTimelineData timeline, final LoanSummaryData loanSummary,
|
||||
final BigDecimal feeChargesDueAtDisbursementCharged) {
|
||||
|
||||
final LoanScheduleData repaymentSchedule = null;
|
||||
final Collection<LoanTransactionData> transactions = null;
|
||||
@@ -405,10 +414,11 @@ public class LoanAccountData {
|
||||
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
|
||||
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionStrategyId, amortizationType, interestRatePerPeriod,
|
||||
interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType, expectedFirstRepaymentOnDate,
|
||||
interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule, transactions, charges, collateral,
|
||||
guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
|
||||
interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions,
|
||||
charges, collateral, guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
|
||||
loanCollateralOptions);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -433,10 +443,10 @@ public class LoanAccountData {
|
||||
acc.repaymentEvery, acc.repaymentFrequencyType, acc.transactionProcessingStrategyId, acc.amortizationType,
|
||||
acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
|
||||
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.interestChargedFromDate, acc.timeline,
|
||||
acc.totalFeeChargesAtDisbursement, repaymentSchedule, transactions, charges, collateral, guarantors, productOptions,
|
||||
termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions,
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
|
||||
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
|
||||
acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors,
|
||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
|
||||
}
|
||||
|
||||
private LoanAccountData(
|
||||
@@ -477,11 +487,12 @@ public class LoanAccountData {
|
||||
final LocalDate expectedFirstRepaymentOnDate,
|
||||
final LocalDate interestChargedFromDate,
|
||||
final LoanApplicationTimelineData timeline,
|
||||
final BigDecimal totalFeeChargesAtDisbursement, //
|
||||
final LoanScheduleData repaymentSchedule, final Collection<LoanTransactionData> transactions,
|
||||
final Collection<LoanChargeData> charges, final Collection<LoanCollateralData> collateral,
|
||||
final Collection<GuarantorData> guarantors, final Collection<LoanProductData> productOptions,
|
||||
final Collection<EnumOptionData> termFrequencyTypeOptions, final Collection<EnumOptionData> repaymentFrequencyTypeOptions,
|
||||
final LoanSummaryData summary, //
|
||||
final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule,
|
||||
final Collection<LoanTransactionData> transactions, final Collection<LoanChargeData> charges,
|
||||
final Collection<LoanCollateralData> collateral, final Collection<GuarantorData> guarantors,
|
||||
final Collection<LoanProductData> productOptions, final Collection<EnumOptionData> termFrequencyTypeOptions,
|
||||
final Collection<EnumOptionData> repaymentFrequencyTypeOptions,
|
||||
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions,
|
||||
final Collection<EnumOptionData> interestRateFrequencyTypeOptions, final Collection<EnumOptionData> amortizationTypeOptions,
|
||||
final Collection<EnumOptionData> interestTypeOptions, final Collection<EnumOptionData> interestCalculationPeriodTypeOptions,
|
||||
@@ -527,7 +538,7 @@ public class LoanAccountData {
|
||||
this.timeline = timeline;
|
||||
|
||||
// totals
|
||||
this.totalFeeChargesAtDisbursement = totalFeeChargesAtDisbursement;
|
||||
this.summary = summary;
|
||||
|
||||
// associations
|
||||
this.repaymentSchedule = repaymentSchedule;
|
||||
@@ -555,7 +566,7 @@ public class LoanAccountData {
|
||||
|
||||
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
||||
return this.timeline.repaymentScheduleRelatedData(this.currency, this.principal, this.inArrearsTolerance,
|
||||
this.totalFeeChargesAtDisbursement);
|
||||
this.feeChargesAtDisbursementCharged);
|
||||
}
|
||||
|
||||
public Long officeId() {
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing loan summary information.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LoanSummaryData {
|
||||
|
||||
private final CurrencyData currency;
|
||||
private final BigDecimal principalDisbursed;
|
||||
private final BigDecimal principalPaid;
|
||||
private final BigDecimal principalWrittenOff;
|
||||
private final BigDecimal principalOutstanding;
|
||||
private final BigDecimal principalOverdue;
|
||||
private final BigDecimal interestCharged;
|
||||
private final BigDecimal interestPaid;
|
||||
private final BigDecimal interestWaived;
|
||||
private final BigDecimal interestWrittenOff;
|
||||
private final BigDecimal interestOutstanding;
|
||||
private final BigDecimal interestOverdue;
|
||||
private final BigDecimal feeChargesCharged;
|
||||
private final BigDecimal feeChargesDueAtDisbursementCharged;
|
||||
private final BigDecimal feeChargesPaid;
|
||||
private final BigDecimal feeChargesWaived;
|
||||
private final BigDecimal feeChargesWrittenOff;
|
||||
private final BigDecimal feeChargesOutstanding;
|
||||
private final BigDecimal feeChargesOverdue;
|
||||
private final BigDecimal penaltyChargesCharged;
|
||||
private final BigDecimal penaltyChargesPaid;
|
||||
private final BigDecimal penaltyChargesWaived;
|
||||
private final BigDecimal penaltyChargesWrittenOff;
|
||||
private final BigDecimal penaltyChargesOutstanding;
|
||||
private final BigDecimal penaltyChargesOverdue;
|
||||
private final BigDecimal totalExpectedRepayment;
|
||||
private final BigDecimal totalRepayment;
|
||||
private final BigDecimal totalExpectedCostOfLoan;
|
||||
private final BigDecimal totalCostOfLoan;
|
||||
private final BigDecimal totalWaived;
|
||||
private final BigDecimal totalWrittenOff;
|
||||
private final BigDecimal totalOutstanding;
|
||||
private final BigDecimal totalOverdue;
|
||||
private final LocalDate overdueSinceDate;
|
||||
|
||||
public LoanSummaryData(final CurrencyData currency, final BigDecimal principalDisbursed, final BigDecimal principalPaid,
|
||||
final BigDecimal principalWrittenOff, final BigDecimal principalOutstanding, final BigDecimal principalOverdue,
|
||||
final BigDecimal interestCharged, final BigDecimal interestPaid, final BigDecimal interestWaived,
|
||||
final BigDecimal interestWrittenOff, final BigDecimal interestOutstanding, final BigDecimal interestOverdue,
|
||||
final BigDecimal feeChargesCharged, final BigDecimal feeChargesDueAtDisbursementCharged, final BigDecimal feeChargesPaid,
|
||||
final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff, final BigDecimal feeChargesOutstanding,
|
||||
final BigDecimal feeChargesOverdue, final BigDecimal penaltyChargesCharged, final BigDecimal penaltyChargesPaid,
|
||||
final BigDecimal penaltyChargesWaived, final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesOutstanding,
|
||||
final BigDecimal penaltyChargesOverdue, final BigDecimal totalExpectedRepayment, final BigDecimal totalRepayment,
|
||||
final BigDecimal totalExpectedCostOfLoan, final BigDecimal totalCostOfLoan, final BigDecimal totalWaived,
|
||||
final BigDecimal totalWrittenOff, final BigDecimal totalOutstanding, final BigDecimal totalOverdue,
|
||||
final LocalDate overdueSinceDate) {
|
||||
this.currency = currency;
|
||||
this.principalDisbursed = principalDisbursed;
|
||||
this.principalPaid = principalPaid;
|
||||
this.principalWrittenOff = principalWrittenOff;
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
this.principalOverdue = principalOverdue;
|
||||
this.interestCharged = interestCharged;
|
||||
this.interestPaid = interestPaid;
|
||||
this.interestWaived = interestWaived;
|
||||
this.interestWrittenOff = interestWrittenOff;
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
this.interestOverdue = interestOverdue;
|
||||
this.feeChargesCharged = feeChargesCharged;
|
||||
this.feeChargesDueAtDisbursementCharged = feeChargesDueAtDisbursementCharged;
|
||||
this.feeChargesPaid = feeChargesPaid;
|
||||
this.feeChargesWaived = feeChargesWaived;
|
||||
this.feeChargesWrittenOff = feeChargesWrittenOff;
|
||||
this.feeChargesOutstanding = feeChargesOutstanding;
|
||||
this.feeChargesOverdue = feeChargesOverdue;
|
||||
this.penaltyChargesCharged = penaltyChargesCharged;
|
||||
this.penaltyChargesPaid = penaltyChargesPaid;
|
||||
this.penaltyChargesWaived = penaltyChargesWaived;
|
||||
this.penaltyChargesWrittenOff = penaltyChargesWrittenOff;
|
||||
this.penaltyChargesOutstanding = penaltyChargesOutstanding;
|
||||
this.penaltyChargesOverdue = penaltyChargesOverdue;
|
||||
this.totalExpectedRepayment = totalExpectedRepayment;
|
||||
this.totalRepayment = totalRepayment;
|
||||
this.totalExpectedCostOfLoan = totalExpectedCostOfLoan;
|
||||
this.totalCostOfLoan = totalCostOfLoan;
|
||||
this.totalWaived = totalWaived;
|
||||
this.totalWrittenOff = totalWrittenOff;
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
this.totalOverdue = totalOverdue;
|
||||
this.overdueSinceDate = overdueSinceDate;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -46,7 +46,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
|
||||
// re-process loan charges over repayment periods (picking up on waived
|
||||
// loan charges)
|
||||
LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
|
||||
LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(currency, disbursementDate, installments, charges);
|
||||
|
||||
for (LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
if (currentInstallment.isPrincipalCompleted(currency)) {
|
||||
// FIXME - KW - if auto waiving interest need to create
|
||||
// another transaction to handle this.
|
||||
currentInstallment.waiveInterestComponent(currentInstallment.getInterest(currency));
|
||||
currentInstallment.waiveInterestComponent(currentInstallment.getInterestCharged(currency));
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
+339
-254
@@ -40,7 +40,6 @@ import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
@@ -73,11 +72,12 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingS
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "loan_account_no_UNIQUE"),
|
||||
@UniqueConstraint(columnNames = { "external_id" }, name = "loan_externalid_UNIQUE") })
|
||||
public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
||||
private String accountNumber;
|
||||
@@ -135,6 +135,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@JoinColumn(name = "submittedon_userid", nullable = true)
|
||||
private AppUser submittedBy;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "rejectedon_date")
|
||||
private Date rejectedOnDate;
|
||||
@@ -176,6 +177,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@JoinColumn(name = "disbursedon_userid", nullable = true)
|
||||
private AppUser disbursedBy;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "closedon_date")
|
||||
private Date closedOnDate;
|
||||
@@ -185,6 +187,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@JoinColumn(name = "closedon_userid", nullable = true)
|
||||
private AppUser closedBy;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "writtenoffon_date")
|
||||
private Date writtenOffOnDate;
|
||||
@@ -193,10 +196,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@Column(name = "rescheduledon_date")
|
||||
private Date rescheduledOnDate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "expected_maturedon_date")
|
||||
private Date expectedMaturityDate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "maturedon_date")
|
||||
private Date actualMaturityDate;
|
||||
@@ -234,14 +239,123 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
|
||||
private final List<LoanTransaction> loanTransactions = new ArrayList<LoanTransaction>();
|
||||
|
||||
// derived totals fields
|
||||
@Column(name = "principal_disbursed_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalDisbursed;
|
||||
|
||||
@Column(name = "principal_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalRepaid;
|
||||
|
||||
@Column(name = "principal_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalWrittenOff;
|
||||
|
||||
@Column(name = "principal_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalOutstanding;
|
||||
|
||||
@Column(name = "principal_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalOverdue;
|
||||
|
||||
@Column(name = "interest_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestCharged;
|
||||
|
||||
@Column(name = "interest_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestRepaid;
|
||||
|
||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestWaived;
|
||||
|
||||
@Column(name = "interest_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestWrittenOff;
|
||||
|
||||
@Column(name = "interest_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestOutstanding;
|
||||
|
||||
@Column(name = "interest_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestOverdue;
|
||||
|
||||
@Column(name = "fee_charges_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesCharged;
|
||||
|
||||
@Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalChargesDueAtDisbursement;
|
||||
|
||||
@Transient
|
||||
private boolean accountNumberRequiresAutoGeneration = false;
|
||||
@Column(name = "fee_charges_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesRepaid;
|
||||
|
||||
@Column(name = "fee_charges_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesWaived;
|
||||
|
||||
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesWrittenOff;
|
||||
|
||||
@Column(name = "fee_charges_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesOutstanding;
|
||||
|
||||
@Column(name = "fee_charges_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesOverdue;
|
||||
|
||||
@Column(name = "penalty_charges_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesCharged;
|
||||
|
||||
@Column(name = "penalty_charges_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesRepaid;
|
||||
|
||||
@Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesWaived;
|
||||
|
||||
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesWrittenOff;
|
||||
|
||||
@Column(name = "penalty_charges_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesOutstanding;
|
||||
|
||||
@Column(name = "penalty_charges_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesOverdue;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_expected_repayment_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalExpectedRepayment;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_repayment_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalRepayment;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_expected_costofloan_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalExpectedCostOfLoan;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_costofloan_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalCostOfLoan;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalWaived;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalWrittenOff;
|
||||
|
||||
@Column(name = "total_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOutstanding;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOverdue;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "overdue_since_date_derived")
|
||||
private Date overdueSinceDate;
|
||||
|
||||
@Transient
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory();
|
||||
private boolean accountNumberRequiresAutoGeneration = false;
|
||||
@Transient
|
||||
private LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
||||
@Transient
|
||||
private LoanLifecycleStateMachine loanLifecycleStateMachine;
|
||||
@Transient
|
||||
private LoanSummaryWrapper loanSummaryWrapper;
|
||||
|
||||
public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final LoanProduct loanProduct,
|
||||
final Fund fund, final Staff officer, final CodeValue loanPurpose,
|
||||
@@ -385,7 +499,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
updateTotalChargesDueAtDisbursement();
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
|
||||
if (!loanCharge.isDueAtDisbursement()) {
|
||||
@@ -394,9 +508,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
} else {
|
||||
// just reprocess the loan schedule only for now.
|
||||
LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
|
||||
LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
}
|
||||
|
||||
private void validateLoanIsNotClosed(final LoanCharge loanCharge) {
|
||||
@@ -443,13 +559,15 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loanCharge);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
}
|
||||
|
||||
private void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final LoanCharge loanCharge) {
|
||||
@@ -491,7 +609,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
updateTotalChargesDueAtDisbursement();
|
||||
}
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
if (!loanCharge.isDueAtDisbursement()) {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
@@ -499,10 +617,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
} else {
|
||||
// reprocess loan schedule based on charge been waived.
|
||||
LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
|
||||
LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@@ -534,7 +654,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
// Waive of charges whose due date falls after latest 'repayment'
|
||||
// transaction dont require entire loan schedule to be reprocessed.
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
@@ -542,10 +662,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
} else {
|
||||
// reprocess loan schedule based on charge been waived.
|
||||
LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
|
||||
LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
|
||||
doPostLoanTransactionChecks(waiveLoanChargeTransaction.getTransactionDate(), loanLifecycleStateMachine);
|
||||
|
||||
return waiveLoanChargeTransaction;
|
||||
@@ -628,17 +750,155 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
// already against it - then need to re-process it
|
||||
final List<LoanTransaction> repaymentsOrWaivers = retreiveListOfTransactionsPostDisbursement();
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), repaymentsOrWaivers, getCurrency(),
|
||||
this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
}
|
||||
|
||||
public void updateLoanScheduleDependentDerivedFields() {
|
||||
private void updateLoanScheduleDependentDerivedFields() {
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
this.actualMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
}
|
||||
|
||||
private void updateLoanSummaryDerivedFields(final LoanSummaryWrapper summary) {
|
||||
|
||||
final Money principal = this.loanRepaymentScheduleDetail.getPrincipal();
|
||||
final MonetaryCurrency currency = loanCurrency();
|
||||
|
||||
if (isNotDisbursed()) {
|
||||
this.totalPrincipalDisbursed = BigDecimal.ZERO;
|
||||
this.totalPrincipalRepaid = BigDecimal.ZERO;
|
||||
this.totalPrincipalWrittenOff = BigDecimal.ZERO;
|
||||
this.totalPrincipalOutstanding = BigDecimal.ZERO;
|
||||
this.totalPrincipalOverdue = BigDecimal.ZERO;
|
||||
this.totalInterestCharged = BigDecimal.ZERO;
|
||||
this.totalInterestRepaid = BigDecimal.ZERO;
|
||||
this.totalInterestWaived = BigDecimal.ZERO;
|
||||
this.totalInterestWrittenOff = BigDecimal.ZERO;
|
||||
this.totalInterestOutstanding = BigDecimal.ZERO;
|
||||
this.totalInterestOverdue = BigDecimal.ZERO;
|
||||
this.totalFeeChargesCharged = BigDecimal.ZERO;
|
||||
this.totalFeeChargesRepaid = BigDecimal.ZERO;
|
||||
this.totalFeeChargesWaived = BigDecimal.ZERO;
|
||||
this.totalFeeChargesWrittenOff = BigDecimal.ZERO;
|
||||
this.totalFeeChargesOutstanding = BigDecimal.ZERO;
|
||||
this.totalFeeChargesOverdue = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesCharged = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesRepaid = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesWaived = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesWrittenOff = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesOutstanding = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesOverdue = BigDecimal.ZERO;
|
||||
this.totalExpectedRepayment = BigDecimal.ZERO;
|
||||
this.totalRepayment = BigDecimal.ZERO;
|
||||
this.totalExpectedCostOfLoan = BigDecimal.ZERO;
|
||||
this.totalCostOfLoan = BigDecimal.ZERO;
|
||||
this.totalWaived = BigDecimal.ZERO;
|
||||
this.totalWrittenOff = BigDecimal.ZERO;
|
||||
this.totalOutstanding = BigDecimal.ZERO;
|
||||
this.totalOverdue = BigDecimal.ZERO;
|
||||
this.overdueSinceDate = null;
|
||||
} else {
|
||||
this.totalPrincipalDisbursed = principal.getAmount();
|
||||
this.totalPrincipalRepaid = summary.calculateTotalPrincipalRepaid(this.repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalPrincipalWrittenOff = summary.calculateTotalPrincipalWrittenOff(this.repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
this.totalPrincipalOutstanding = principal.minus(totalPrincipalRepaid).minus(totalPrincipalWrittenOff).getAmount();
|
||||
this.totalPrincipalOverdue = summary.calculateTotalPrincipalOverdueOn(this.repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
|
||||
final Money totalInterestCharged = summary.calculateTotalInterestCharged(this.repaymentScheduleInstallments, currency);
|
||||
this.totalInterestCharged = totalInterestCharged.getAmount();
|
||||
this.totalInterestRepaid = summary.calculateTotalInterestRepaid(this.repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalInterestWaived = summary.calculateTotalInterestWaived(this.repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalInterestWrittenOff = summary.calculateTotalInterestWrittenOff(this.repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
if (totalInterestCharged.isGreaterThanZero()) {
|
||||
this.totalInterestOutstanding = totalInterestCharged.minus(this.totalInterestRepaid).minus(this.totalInterestWaived)
|
||||
.minus(this.totalInterestWrittenOff).getAmount();
|
||||
this.totalInterestOverdue = summary.calculateTotalInterestOverdueOn(this.repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
}
|
||||
|
||||
final Money totalFeeChargesCharged = summary.calculateTotalFeeChargesCharged(this.repaymentScheduleInstallments, currency);
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged.getAmount();
|
||||
this.totalFeeChargesRepaid = summary.calculateTotalFeeChargesRepaid(this.repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalFeeChargesWaived = summary.calculateTotalFeeChargesWaived(this.repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalFeeChargesWrittenOff = summary.calculateTotalFeeChargesWrittenOff(this.repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
if (totalFeeChargesCharged.isGreaterThanZero()) {
|
||||
this.totalFeeChargesOutstanding = totalFeeChargesCharged.minus(this.totalFeeChargesRepaid)
|
||||
.minus(this.totalFeeChargesWaived).minus(this.totalFeeChargesWrittenOff).getAmount();
|
||||
this.totalFeeChargesOverdue = summary.calculateTotalFeeChargesOverdueOn(this.repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
}
|
||||
|
||||
final Money totalPenaltyChargesCharged = summary.calculateTotalPenaltyChargesCharged(this.repaymentScheduleInstallments,
|
||||
currency);
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged.getAmount();
|
||||
this.totalPenaltyChargesRepaid = summary.calculateTotalPenaltyChargesRepaid(this.repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
this.totalPenaltyChargesWaived = summary.calculateTotalPenaltyChargesWaived(this.repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
this.totalPenaltyChargesWrittenOff = summary.calculateTotalPenaltyChargesWrittenOff(this.repaymentScheduleInstallments,
|
||||
currency).getAmount();
|
||||
|
||||
if (totalPenaltyChargesCharged.isGreaterThanZero()) {
|
||||
this.totalPenaltyChargesOutstanding = totalPenaltyChargesCharged.minus(this.totalPenaltyChargesRepaid)
|
||||
.minus(this.totalPenaltyChargesWaived).minus(this.totalPenaltyChargesWrittenOff).getAmount();
|
||||
this.totalPenaltyChargesOverdue = summary.calculateTotalPenaltyChargesOverdueOn(this.repaymentScheduleInstallments,
|
||||
currency, DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
}
|
||||
|
||||
final Money totalExpectedRepayment = Money.of(currency, this.totalPrincipalDisbursed).plus(this.totalInterestCharged)
|
||||
.plus(this.totalFeeChargesCharged).plus(this.totalPenaltyChargesCharged);
|
||||
this.totalExpectedRepayment = totalExpectedRepayment.getAmount();
|
||||
|
||||
final Money totalRepayment = Money.of(currency, this.totalPrincipalRepaid).plus(this.totalInterestRepaid)
|
||||
.plus(this.totalFeeChargesRepaid).plus(this.totalPenaltyChargesRepaid);
|
||||
this.totalRepayment = totalRepayment.getAmount();
|
||||
|
||||
final Money totalExpectedCostOfLoan = Money.of(currency, this.totalInterestCharged).plus(this.totalFeeChargesCharged)
|
||||
.plus(this.totalPenaltyChargesCharged);
|
||||
this.totalExpectedCostOfLoan = totalExpectedCostOfLoan.getAmount();
|
||||
|
||||
final Money totalCostOfLoan = Money.of(currency, this.totalInterestRepaid).plus(this.totalFeeChargesRepaid)
|
||||
.plus(this.totalPenaltyChargesRepaid);
|
||||
this.totalCostOfLoan = totalCostOfLoan.getAmount();
|
||||
|
||||
final Money totalWaived = Money.of(currency, this.totalInterestWaived).plus(this.totalFeeChargesWaived)
|
||||
.plus(this.totalPenaltyChargesWaived);
|
||||
this.totalWaived = totalWaived.getAmount();
|
||||
|
||||
final Money totalWrittenOff = Money.of(currency, this.totalPrincipalWrittenOff).plus(this.totalInterestWrittenOff)
|
||||
.plus(this.totalFeeChargesWrittenOff).plus(this.totalPenaltyChargesWrittenOff);
|
||||
this.totalWrittenOff = totalWrittenOff.getAmount();
|
||||
|
||||
final Money totalOutstanding = Money.of(currency, this.totalPrincipalOutstanding).plus(this.totalInterestOutstanding)
|
||||
.plus(this.totalFeeChargesOutstanding).plus(this.totalPenaltyChargesOutstanding);
|
||||
this.totalOutstanding = totalOutstanding.getAmount();
|
||||
|
||||
final Money totalOverdue = Money.of(currency, this.totalPrincipalOverdue).plus(this.totalInterestOverdue)
|
||||
.plus(this.totalFeeChargesOverdue).plus(this.totalPenaltyChargesOverdue);
|
||||
this.totalOverdue = totalOverdue.getAmount();
|
||||
|
||||
final LocalDate overdueSinceLocalDate = summary.determineOverdueSinceDateFrom(this.repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
if (overdueSinceLocalDate != null) {
|
||||
this.overdueSinceDate = overdueSinceLocalDate.toDate();
|
||||
} else {
|
||||
this.overdueSinceDate = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> loanApplicationModification(final JsonCommand command, final Set<LoanCharge> possiblyModifedLoanCharges,
|
||||
final Set<LoanCollateral> possiblyModifedLoanCollateralItems, final AprCalculator aprCalculator) {
|
||||
|
||||
@@ -1100,13 +1360,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final ApplicationCurrency currency,
|
||||
public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command, final ApplicationCurrency currency,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||
|
||||
updateLoanToPreDisbursalState();
|
||||
updateLoanToPreDisbursalState(this.loanSummaryWrapper);
|
||||
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatus.fromInt(this.loanStatus));
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
@@ -1131,6 +1390,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) {
|
||||
regenerateRepaymentSchedule(currency);
|
||||
} else {
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1164,8 +1425,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
final LoanSchedule loanSchedule = new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, interestRatePerPeriod,
|
||||
interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
|
||||
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, loanTermFrequency,
|
||||
loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(),
|
||||
this.getExpectedFirstRepaymentOnDate(), this.getInterestChargedFromDate(), inArrearsTolerance);
|
||||
loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(), this.getExpectedFirstRepaymentOnDate(),
|
||||
this.getInterestChargedFromDate(), inArrearsTolerance);
|
||||
|
||||
final LoanScheduleData generatedData = loanSchedule.generate();
|
||||
|
||||
@@ -1219,13 +1480,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return disbursementTransaction;
|
||||
}
|
||||
|
||||
public Map<String, Object> undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
public Map<String, Object> undoDisbursal(final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||
|
||||
final LoanStatus currentStatus = LoanStatus.fromInt(this.loanStatus);
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, currentStatus);
|
||||
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, currentStatus);
|
||||
if (!statusEnum.hasStateOf(currentStatus)) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
@@ -1239,7 +1499,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
reverseExistingTransactions();
|
||||
|
||||
updateLoanToPreDisbursalState();
|
||||
updateLoanToPreDisbursalState(this.loanSummaryWrapper);
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
@@ -1252,7 +1512,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLoanToPreDisbursalState() {
|
||||
private void updateLoanToPreDisbursalState(final LoanSummaryWrapper summaryWrapper) {
|
||||
this.actualDisbursementDate = null;
|
||||
|
||||
for (LoanCharge charge : setOfLoanCharges()) {
|
||||
@@ -1263,8 +1523,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
currentInstallment.resetDerivedComponents();
|
||||
}
|
||||
|
||||
LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
|
||||
LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
|
||||
updateLoanSummaryDerivedFields(summaryWrapper);
|
||||
}
|
||||
|
||||
public LoanTransaction waiveInterest(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
@@ -1340,7 +1602,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
}
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
if (isTransactionChronologicallyLatest && adjustedTransaction == null) {
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(), this.repaymentScheduleInstallments,
|
||||
@@ -1351,6 +1613,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
|
||||
doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
|
||||
}
|
||||
|
||||
@@ -1529,31 +1793,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
private boolean isRepaidInFull() {
|
||||
|
||||
MonetaryCurrency currency = loanCurrency();
|
||||
|
||||
Money cumulativeOriginalPrincipalExpected = Money.zero(currency);
|
||||
Money cumulativeOriginalInterestExpected = Money.zero(currency);
|
||||
Money cumulativeOriginalTotalExpected = Money.zero(currency);
|
||||
|
||||
Money cumulativeTotalPaid = Money.zero(currency);
|
||||
Money cumulativeTotalWaived = Money.zero(currency);
|
||||
|
||||
for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) {
|
||||
cumulativeOriginalPrincipalExpected = cumulativeOriginalPrincipalExpected.plus(scheduledRepayment.getPrincipal(currency));
|
||||
cumulativeOriginalInterestExpected = cumulativeOriginalInterestExpected.plus(scheduledRepayment.getInterest(currency));
|
||||
|
||||
cumulativeTotalPaid = cumulativeTotalPaid.plus(scheduledRepayment.getPrincipalCompleted(currency).plus(
|
||||
scheduledRepayment.getInterestCompleted(currency)));
|
||||
cumulativeTotalWaived = cumulativeTotalWaived.plus(scheduledRepayment.getInterestWaived(currency));
|
||||
}
|
||||
|
||||
cumulativeOriginalTotalExpected = cumulativeOriginalPrincipalExpected.plus(cumulativeOriginalInterestExpected);
|
||||
|
||||
Money totalOutstanding = cumulativeOriginalTotalExpected.minus(cumulativeTotalPaid.plus(cumulativeTotalWaived));
|
||||
boolean isRepaidInFull = totalOutstanding.isZero();
|
||||
|
||||
return isRepaidInFull;
|
||||
return Money.of(loanCurrency(), this.totalOutstanding).isZero();
|
||||
}
|
||||
|
||||
private boolean isOverPaid() {
|
||||
@@ -1571,9 +1811,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) {
|
||||
|
||||
cumulativeTotalPaidOnInstallments = cumulativeTotalPaidOnInstallments
|
||||
.plus(scheduledRepayment.getPrincipalCompleted(currency).plus(scheduledRepayment.getInterestCompleted(currency)))
|
||||
.plus(scheduledRepayment.getFeeChargesCompleted(currency))
|
||||
.plus(scheduledRepayment.getPenaltyChargesCompleted(currency));
|
||||
.plus(scheduledRepayment.getPrincipalCompleted(currency).plus(scheduledRepayment.getInterestPaid(currency)))
|
||||
.plus(scheduledRepayment.getFeeChargesPaid(currency)).plus(scheduledRepayment.getPenaltyChargesPaid(currency));
|
||||
|
||||
cumulativeTotalWaivedOnInstallments = cumulativeTotalWaivedOnInstallments.plus(scheduledRepayment.getInterestWaived(currency));
|
||||
}
|
||||
@@ -1630,9 +1869,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
this.loanTransactions.add(loanTransaction);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), this.repaymentScheduleInstallments);
|
||||
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
}
|
||||
|
||||
return loanTransaction;
|
||||
@@ -1663,11 +1904,15 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
LoanTransaction loanTransaction = null;
|
||||
if (isOpen()) {
|
||||
// 1. check total outstanding
|
||||
final Money outstanding = getTotalOutstanding();
|
||||
final Money outstanding = Money.of(loanCurrency(), this.totalOutstanding);
|
||||
if (outstanding.isGreaterThanZero() && getInArrearsTolerance().isGreaterThanOrEqualTo(outstanding)) {
|
||||
|
||||
updateLoanForClosure(closureDate, loanLifecycleStateMachine, changes);
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus));
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
changes.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
}
|
||||
this.closedOnDate = closureDate.toDate();
|
||||
|
||||
loanTransaction = LoanTransaction.writeoff(this, closureDate);
|
||||
boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions);
|
||||
@@ -1679,11 +1924,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
this.loanTransactions.add(loanTransaction);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(),
|
||||
this.repaymentScheduleInstallments);
|
||||
|
||||
updateLoanSummaryDerivedFields(this.loanSummaryWrapper);
|
||||
} else if (outstanding.isGreaterThanZero()) {
|
||||
final String errorMessage = "A loan with money outstanding cannot be closed";
|
||||
throw new InvalidLoanStateTransitionException("close", "loan.has.money.outstanding", errorMessage, outstanding.toString());
|
||||
@@ -1696,7 +1942,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
// TODO - KW - technically should set somewhere that this loan
|
||||
// has
|
||||
// 'overpaid' amount
|
||||
updateLoanForClosure(closureDate, loanLifecycleStateMachine, changes);
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus));
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
changes.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
}
|
||||
this.closedOnDate = closureDate.toDate();
|
||||
} else if (totalLoanOverpayment.isGreaterThanZero()) {
|
||||
final String errorMessage = "The loan is marked as 'Overpaid' and cannot be moved to 'Closed (obligations met).";
|
||||
throw new InvalidLoanStateTransitionException("close", "loan.is.overpaid", errorMessage, totalLoanOverpayment.toString());
|
||||
@@ -1706,26 +1957,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return loanTransaction;
|
||||
}
|
||||
|
||||
private Money getTotalOutstanding() {
|
||||
Money totalOutstanding = Money.zero(loanCurrency());
|
||||
|
||||
final LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
|
||||
totalOutstanding = wrapper.calculateTotalOutstanding(loanCurrency(), this.repaymentScheduleInstallments);
|
||||
|
||||
return totalOutstanding;
|
||||
}
|
||||
|
||||
private void updateLoanForClosure(final LocalDate closureDate, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||
final Map<String, Object> changes) {
|
||||
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus));
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
changes.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
}
|
||||
this.closedOnDate = closureDate.toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaviour added to comply with capability of previous mifos product to
|
||||
* support easier transition to mifosx platform.
|
||||
@@ -1773,73 +2004,34 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return status().isSubmittedAndPendingApproval();
|
||||
}
|
||||
|
||||
public boolean isApproved() {
|
||||
return status().isApproved();
|
||||
}
|
||||
|
||||
public boolean isNotApproved() {
|
||||
return !isApproved();
|
||||
}
|
||||
|
||||
public boolean isWaitingForDisbursal() {
|
||||
return this.isApproved() && this.isNotDisbursed();
|
||||
}
|
||||
|
||||
public boolean isNotDisbursed() {
|
||||
private boolean isNotDisbursed() {
|
||||
return !this.isDisbursed();
|
||||
}
|
||||
|
||||
public boolean isDisbursed() {
|
||||
private boolean isDisbursed() {
|
||||
return hasDisbursementTransaction();
|
||||
}
|
||||
|
||||
public boolean isUndoDisbursalAllowed() {
|
||||
return isDisbursed() && this.hasNoRepaymentTransaction();
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
private boolean isClosed() {
|
||||
return status().isClosed() || this.isCancelled();
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
private boolean isCancelled() {
|
||||
return this.isRejected() || this.isWithdrawn();
|
||||
}
|
||||
|
||||
public boolean isWithdrawn() {
|
||||
private boolean isWithdrawn() {
|
||||
return status().isWithdrawnByClient();
|
||||
}
|
||||
|
||||
public boolean isRejected() {
|
||||
private boolean isRejected() {
|
||||
return status().isRejected();
|
||||
}
|
||||
|
||||
public boolean isNotClosed() {
|
||||
return !this.isClosed();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
private boolean isOpen() {
|
||||
return status().isActive();
|
||||
}
|
||||
|
||||
public boolean isOpenWithNoRepaymentMade() {
|
||||
return this.isOpen() && hasNoRepaymentTransaction();
|
||||
}
|
||||
|
||||
private boolean hasNoRepaymentTransaction() {
|
||||
return !hasRepaymentTransaction();
|
||||
}
|
||||
|
||||
private boolean hasRepaymentTransaction() {
|
||||
boolean hasRepaymentTransaction = false;
|
||||
for (LoanTransaction loanTransaction : this.loanTransactions) {
|
||||
if (loanTransaction.isRepayment()) {
|
||||
hasRepaymentTransaction = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hasRepaymentTransaction;
|
||||
}
|
||||
|
||||
private boolean hasDisbursementTransaction() {
|
||||
boolean hasRepaymentTransaction = false;
|
||||
for (LoanTransaction loanTransaction : this.loanTransactions) {
|
||||
@@ -1851,35 +2043,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return hasRepaymentTransaction;
|
||||
}
|
||||
|
||||
public boolean isOpenWithRepaymentMade() {
|
||||
return this.isOpen() && this.hasRepaymentTransaction();
|
||||
}
|
||||
|
||||
public List<LoanRepaymentScheduleInstallment> getRepaymentScheduleInstallments() {
|
||||
return this.repaymentScheduleInstallments;
|
||||
}
|
||||
|
||||
public String getExternalId() {
|
||||
return this.externalId;
|
||||
}
|
||||
|
||||
public void setExternalId(final String externalSystemIdentifer) {
|
||||
if (StringUtils.isNotBlank(externalSystemIdentifer)) {
|
||||
this.externalId = externalSystemIdentifer.trim();
|
||||
} else {
|
||||
this.externalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalDate getSubmittedOnDate() {
|
||||
private LocalDate getSubmittedOnDate() {
|
||||
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.submittedOnDate), null);
|
||||
}
|
||||
|
||||
public LocalDate getRejectedOnDate() {
|
||||
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.rejectedOnDate), null);
|
||||
}
|
||||
|
||||
public LocalDate getApprovedOnDate() {
|
||||
private LocalDate getApprovedOnDate() {
|
||||
LocalDate date = null;
|
||||
if (this.approvedOnDate != null) {
|
||||
date = new LocalDate(this.approvedOnDate);
|
||||
@@ -1887,35 +2055,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return date;
|
||||
}
|
||||
|
||||
public LocalDate getDisbursedOnDate() {
|
||||
LocalDate date = null;
|
||||
if (this.actualDisbursementDate != null) {
|
||||
date = new LocalDate(this.actualDisbursementDate);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
public LocalDate getClosedOnDate() {
|
||||
LocalDate date = null;
|
||||
if (this.closedOnDate != null) {
|
||||
date = new LocalDate(this.closedOnDate);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
public LocalDate getWrittenOffOnDate() {
|
||||
LocalDate date = null;
|
||||
if (this.writtenOffOnDate != null) {
|
||||
date = new LocalDate(this.writtenOffOnDate);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
public Date getExpectedDisbursedOnDate() {
|
||||
return this.expectedDisbursementDate;
|
||||
}
|
||||
|
||||
public LocalDate getExpectedDisbursedOnLocalDate() {
|
||||
private LocalDate getExpectedDisbursedOnLocalDate() {
|
||||
LocalDate expectedDisbursementDate = null;
|
||||
if (this.expectedDisbursementDate != null) {
|
||||
expectedDisbursementDate = new LocalDate(this.expectedDisbursementDate);
|
||||
@@ -1923,15 +2063,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return expectedDisbursementDate;
|
||||
}
|
||||
|
||||
public LocalDate getExpectedFirstRepaymentOnDate() {
|
||||
LocalDate firstRepaymentDate = null;
|
||||
if (this.expectedFirstRepaymentOnDate != null) {
|
||||
firstRepaymentDate = new LocalDate(this.expectedFirstRepaymentOnDate);
|
||||
}
|
||||
return firstRepaymentDate;
|
||||
}
|
||||
|
||||
public LocalDate getDisbursementDate() {
|
||||
private LocalDate getDisbursementDate() {
|
||||
LocalDate disbursementDate = getExpectedDisbursedOnLocalDate();
|
||||
if (this.actualDisbursementDate != null) {
|
||||
disbursementDate = new LocalDate(this.actualDisbursementDate);
|
||||
@@ -1939,52 +2071,24 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return disbursementDate;
|
||||
}
|
||||
|
||||
public LocalDate getExpectedMaturityDate() {
|
||||
LocalDate possibleMaturityDate = null;
|
||||
if (this.expectedMaturityDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.expectedMaturityDate);
|
||||
private LocalDate getExpectedFirstRepaymentOnDate() {
|
||||
LocalDate firstRepaymentDate = null;
|
||||
if (this.expectedFirstRepaymentOnDate != null) {
|
||||
firstRepaymentDate = new LocalDate(this.expectedFirstRepaymentOnDate);
|
||||
}
|
||||
return possibleMaturityDate;
|
||||
return firstRepaymentDate;
|
||||
}
|
||||
|
||||
public LocalDate getActualMaturityDate() {
|
||||
LocalDate possibleMaturityDate = null;
|
||||
if (this.actualMaturityDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.actualMaturityDate);
|
||||
}
|
||||
return possibleMaturityDate;
|
||||
}
|
||||
|
||||
public LocalDate getMaturityDate() {
|
||||
LocalDate possibleMaturityDate = null;
|
||||
|
||||
if (this.expectedMaturityDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.expectedMaturityDate);
|
||||
}
|
||||
if (this.actualMaturityDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.actualMaturityDate);
|
||||
}
|
||||
return possibleMaturityDate;
|
||||
}
|
||||
|
||||
public Set<LoanCharge> getCharges() {
|
||||
return charges;
|
||||
}
|
||||
|
||||
public void setCharges(final Set<LoanCharge> charges) {
|
||||
this.charges = charges;
|
||||
}
|
||||
|
||||
public void addRepaymentScheduleInstallment(final LoanRepaymentScheduleInstallment installment) {
|
||||
private void addRepaymentScheduleInstallment(final LoanRepaymentScheduleInstallment installment) {
|
||||
installment.updateLoan(this);
|
||||
this.repaymentScheduleInstallments.add(installment);
|
||||
}
|
||||
|
||||
public boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDate actualDisbursedOnDate) {
|
||||
private boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDate actualDisbursedOnDate) {
|
||||
return !new LocalDate(this.expectedDisbursementDate).isEqual(actualDisbursedOnDate);
|
||||
}
|
||||
|
||||
public boolean isRepaymentScheduleRegenerationRequiredForDisbursement(final LocalDate actualDisbursementDate) {
|
||||
private boolean isRepaymentScheduleRegenerationRequiredForDisbursement(final LocalDate actualDisbursementDate) {
|
||||
return isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate);
|
||||
}
|
||||
|
||||
@@ -2029,10 +2133,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return this.loanRepaymentScheduleDetail.getInArrearsTolerance();
|
||||
}
|
||||
|
||||
public boolean identifiedBy(final String identifier) {
|
||||
return identifier.equalsIgnoreCase(this.externalId) || identifier.equalsIgnoreCase(this.getId().toString());
|
||||
}
|
||||
|
||||
public boolean hasIdentifyOf(final Long loanId) {
|
||||
return loanId.equals(this.getId());
|
||||
}
|
||||
@@ -2049,7 +2149,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return matchesCurrentLoanOfficer;
|
||||
}
|
||||
|
||||
public LocalDate getInterestChargedFromDate() {
|
||||
private LocalDate getInterestChargedFromDate() {
|
||||
LocalDate interestChargedFrom = null;
|
||||
if (this.interestChargedFromDate != null) {
|
||||
interestChargedFrom = new LocalDate(this.interestChargedFromDate);
|
||||
@@ -2057,29 +2157,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return interestChargedFrom;
|
||||
}
|
||||
|
||||
public LocalDate getLoanStatusSinceDate() {
|
||||
|
||||
LocalDate statusSinceDate = getSubmittedOnDate();
|
||||
if (isApproved()) {
|
||||
statusSinceDate = new LocalDate(this.approvedOnDate);
|
||||
}
|
||||
|
||||
if (isDisbursed()) {
|
||||
statusSinceDate = new LocalDate(this.actualDisbursementDate);
|
||||
}
|
||||
|
||||
if (isClosed()) {
|
||||
statusSinceDate = new LocalDate(this.closedOnDate);
|
||||
}
|
||||
|
||||
return statusSinceDate;
|
||||
}
|
||||
|
||||
public Money getPrincpal() {
|
||||
return this.loanRepaymentScheduleDetail.getPrincipal();
|
||||
}
|
||||
|
||||
public Money getTotalChargesDueAtDisbursement() {
|
||||
private Money getTotalChargesDueAtDisbursement() {
|
||||
return Money.of(getCurrency(), this.totalChargesDueAtDisbursement);
|
||||
}
|
||||
|
||||
@@ -2155,10 +2237,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return latestRecordWithNoEndDate;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public Long getClientId() {
|
||||
Long clientId = null;
|
||||
if (this.client != null) {
|
||||
@@ -2223,4 +2301,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
accountingBridgeData.put("newLoanTransactions", newLoanTransactions);
|
||||
return accountingBridgeData;
|
||||
}
|
||||
|
||||
public void setHelpers(final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanSummaryWrapper loanSummaryWrapper,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory) {
|
||||
this.loanLifecycleStateMachine = loanLifecycleStateMachine;
|
||||
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||
this.transactionProcessorFactory = transactionProcessorFactory;
|
||||
}
|
||||
}
|
||||
+38
-38
@@ -51,10 +51,10 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
private BigDecimal principalWrittenOff;
|
||||
|
||||
@Column(name = "interest_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interest;
|
||||
private BigDecimal interestCharged;
|
||||
|
||||
@Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestCompleted;
|
||||
private BigDecimal interestPaid;
|
||||
|
||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestWaived;
|
||||
@@ -63,10 +63,10 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
private BigDecimal interestWrittenOff;
|
||||
|
||||
@Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeCharges;
|
||||
private BigDecimal feeChargesCharged;
|
||||
|
||||
@Column(name = "fee_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesCompleted;
|
||||
private BigDecimal feeChargesPaid;
|
||||
|
||||
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesWrittenOff;
|
||||
@@ -78,7 +78,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
private BigDecimal penaltyCharges;
|
||||
|
||||
@Column(name = "penalty_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesCompleted;
|
||||
private BigDecimal penaltyChargesPaid;
|
||||
|
||||
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesWrittenOff;
|
||||
@@ -104,8 +104,8 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
this.fromDate = fromDate.toDateMidnight().toDate();
|
||||
this.dueDate = dueDate.toDateMidnight().toDate();
|
||||
this.principal = defaultToNullIfZero(principal);
|
||||
this.interest = defaultToNullIfZero(interest);
|
||||
this.feeCharges = defaultToNullIfZero(feeCharges);
|
||||
this.interestCharged = defaultToNullIfZero(interest);
|
||||
this.feeChargesCharged = defaultToNullIfZero(feeCharges);
|
||||
this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
|
||||
this.completed = false;
|
||||
}
|
||||
@@ -156,12 +156,12 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
return getPrincipal(currency).minus(principalAccountedFor);
|
||||
}
|
||||
|
||||
public Money getInterest(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interest);
|
||||
public Money getInterestCharged(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestCharged);
|
||||
}
|
||||
|
||||
public Money getInterestCompleted(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestCompleted);
|
||||
public Money getInterestPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestPaid);
|
||||
}
|
||||
|
||||
public Money getInterestWaived(final MonetaryCurrency currency) {
|
||||
@@ -173,17 +173,17 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
}
|
||||
|
||||
public Money getInterestOutstanding(final MonetaryCurrency currency) {
|
||||
final Money interestAccountedFor = getInterestCompleted(currency).plus(getInterestWaived(currency)).plus(
|
||||
final Money interestAccountedFor = getInterestPaid(currency).plus(getInterestWaived(currency)).plus(
|
||||
getInterestWrittenOff(currency));
|
||||
return getInterest(currency).minus(interestAccountedFor);
|
||||
return getInterestCharged(currency).minus(interestAccountedFor);
|
||||
}
|
||||
|
||||
public Money getFeeCharges(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeCharges);
|
||||
public Money getFeeChargesCharged(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesCharged);
|
||||
}
|
||||
|
||||
public Money getFeeChargesCompleted(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesCompleted);
|
||||
public Money getFeeChargesPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesPaid);
|
||||
}
|
||||
|
||||
public Money getFeeChargesWaived(final MonetaryCurrency currency) {
|
||||
@@ -195,17 +195,17 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
}
|
||||
|
||||
public Money getFeeChargesOutstanding(final MonetaryCurrency currency) {
|
||||
final Money feeChargesAccountedFor = getFeeChargesCompleted(currency).plus(getFeeChargesWaived(currency)).plus(
|
||||
final Money feeChargesAccountedFor = getFeeChargesPaid(currency).plus(getFeeChargesWaived(currency)).plus(
|
||||
getFeeChargesWrittenOff(currency));
|
||||
return getFeeCharges(currency).minus(feeChargesAccountedFor);
|
||||
return getFeeChargesCharged(currency).minus(feeChargesAccountedFor);
|
||||
}
|
||||
|
||||
public Money getPenaltyCharges(final MonetaryCurrency currency) {
|
||||
public Money getPenaltyChargesCharged(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyCharges);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesCompleted(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesCompleted);
|
||||
public Money getPenaltyChargesPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesPaid);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesWaived(final MonetaryCurrency currency) {
|
||||
@@ -217,9 +217,9 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesOutstanding(final MonetaryCurrency currency) {
|
||||
final Money feeChargesAccountedFor = getPenaltyChargesCompleted(currency).plus(getPenaltyChargesWaived(currency)).plus(
|
||||
final Money feeChargesAccountedFor = getPenaltyChargesPaid(currency).plus(getPenaltyChargesWaived(currency)).plus(
|
||||
getPenaltyChargesWrittenOff(currency));
|
||||
return getPenaltyCharges(currency).minus(feeChargesAccountedFor);
|
||||
return getPenaltyChargesCharged(currency).minus(feeChargesAccountedFor);
|
||||
}
|
||||
|
||||
public boolean isInterestDue(final MonetaryCurrency currency) {
|
||||
@@ -227,7 +227,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
}
|
||||
|
||||
public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) {
|
||||
return getPrincipal(currency).plus(getInterest(currency));
|
||||
return getPrincipal(currency).plus(getInterestCharged(currency));
|
||||
}
|
||||
|
||||
public Money getTotalOutstanding(final MonetaryCurrency currency) {
|
||||
@@ -258,13 +258,13 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
public void resetDerivedComponents() {
|
||||
this.principalCompleted = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.interestCompleted = null;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.feeChargesCompleted = null;
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.penaltyChargesCompleted = null;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
|
||||
@@ -278,14 +278,14 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
|
||||
final Money penaltyChargesDue = getPenaltyChargesOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesDue)) {
|
||||
this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(penaltyChargesDue).getAmount();
|
||||
this.penaltyChargesPaid = getPenaltyChargesPaid(currency).plus(penaltyChargesDue).getAmount();
|
||||
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(penaltyChargesDue);
|
||||
} else {
|
||||
this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||
this.penaltyChargesPaid = getPenaltyChargesPaid(currency).plus(transactionAmountRemaining).getAmount();
|
||||
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.penaltyChargesCompleted = defaultToNullIfZero(this.penaltyChargesCompleted);
|
||||
this.penaltyChargesPaid = defaultToNullIfZero(this.penaltyChargesPaid);
|
||||
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
@@ -299,14 +299,14 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
|
||||
final Money feeChargesDue = getFeeChargesOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesDue)) {
|
||||
this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(feeChargesDue).getAmount();
|
||||
this.feeChargesPaid = getFeeChargesPaid(currency).plus(feeChargesDue).getAmount();
|
||||
feePortionOfTransaction = feePortionOfTransaction.plus(feeChargesDue);
|
||||
} else {
|
||||
this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||
this.feeChargesPaid = getFeeChargesPaid(currency).plus(transactionAmountRemaining).getAmount();
|
||||
feePortionOfTransaction = feePortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.feeChargesCompleted = defaultToNullIfZero(this.feeChargesCompleted);
|
||||
this.feeChargesPaid = defaultToNullIfZero(this.feeChargesPaid);
|
||||
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
@@ -320,14 +320,14 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
|
||||
final Money interestDue = getInterestOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
|
||||
this.interestCompleted = getInterestCompleted(currency).plus(interestDue).getAmount();
|
||||
this.interestPaid = getInterestPaid(currency).plus(interestDue).getAmount();
|
||||
interestPortionOfTransaction = interestPortionOfTransaction.plus(interestDue);
|
||||
} else {
|
||||
this.interestCompleted = getInterestCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||
this.interestPaid = getInterestPaid(currency).plus(transactionAmountRemaining).getAmount();
|
||||
interestPortionOfTransaction = interestPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.interestCompleted = defaultToNullIfZero(this.interestCompleted);
|
||||
this.interestPaid = defaultToNullIfZero(this.interestPaid);
|
||||
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
@@ -455,7 +455,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
|
||||
public void updateChargePortion(final Money feeChargesDue, final Money feeChargesWaived, final Money feeChargesWrittenOff,
|
||||
final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) {
|
||||
this.feeCharges = defaultToNullIfZero(feeChargesDue.getAmount());
|
||||
this.feeChargesCharged = defaultToNullIfZero(feeChargesDue.getAmount());
|
||||
this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.getAmount());
|
||||
this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.getAmount());
|
||||
this.penaltyCharges = defaultToNullIfZero(penaltyChargesDue.getAmount());
|
||||
|
||||
+1
-19
@@ -15,27 +15,9 @@ import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
/**
|
||||
* A wrapper around loan schedule related data exposing needed behaviour by
|
||||
* loan.
|
||||
*
|
||||
* This wrapper should be side-effect free. It should not attempt to change
|
||||
* state of loan parts passed through to it.
|
||||
*/
|
||||
public class LoanScheduleWrapper {
|
||||
public class LoanRepaymentScheduleProcessingWrapper {
|
||||
|
||||
public Money calculateTotalOutstanding(final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> installments) {
|
||||
|
||||
Money cumulativeValue = Money.zero(currency);
|
||||
|
||||
for (LoanRepaymentScheduleInstallment scheduledRepayment : installments) {
|
||||
cumulativeValue = cumulativeValue.plus(scheduledRepayment.getTotalOutstanding(currency));
|
||||
}
|
||||
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME - KW - this is not a side effect free approach so move this into a
|
||||
* specific wrapper than makes this obvious from the read-only wrapper.
|
||||
*/
|
||||
public void reprocess(final MonetaryCurrency currency, final LocalDate disbursementDate,
|
||||
final List<LoanRepaymentScheduleInstallment> repaymentPeriods, final Set<LoanCharge> loanCharges) {
|
||||
|
||||
+27
-28
@@ -6,36 +6,35 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class LoanRepaymentScheduleTransactionProcessorFactory {
|
||||
|
||||
public LoanRepaymentScheduleTransactionProcessor determineProcessor(final LoanTransactionProcessingStrategy transactionProcessingStrategy) {
|
||||
public LoanRepaymentScheduleTransactionProcessor determineProcessor(
|
||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy) {
|
||||
|
||||
LoanRepaymentScheduleTransactionProcessor processor = new MifosStyleLoanRepaymentScheduleTransactionProcessor();
|
||||
|
||||
if (transactionProcessingStrategy != null) {
|
||||
|
||||
if (transactionProcessingStrategy.isStandardMifosStrategy()) {
|
||||
processor = new MifosStyleLoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
|
||||
if (transactionProcessingStrategy.isHeavensfamilyStrategy()) {
|
||||
processor = new HeavensFamilyLoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
|
||||
if (transactionProcessingStrategy.isCreocoreStrategy()) {
|
||||
processor = new CreocoreLoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
|
||||
if (transactionProcessingStrategy.isIndianRBIStrategy()) {
|
||||
processor = new RBILoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
return processor;
|
||||
}
|
||||
LoanRepaymentScheduleTransactionProcessor processor = new MifosStyleLoanRepaymentScheduleTransactionProcessor();
|
||||
|
||||
if (transactionProcessingStrategy != null) {
|
||||
|
||||
if (transactionProcessingStrategy.isStandardMifosStrategy()) {
|
||||
processor = new MifosStyleLoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
|
||||
if (transactionProcessingStrategy.isHeavensfamilyStrategy()) {
|
||||
processor = new HeavensFamilyLoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
|
||||
if (transactionProcessingStrategy.isCreocoreStrategy()) {
|
||||
processor = new CreocoreLoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
|
||||
if (transactionProcessingStrategy.isIndianRBIStrategy()) {
|
||||
processor = new RBILoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
return processor;
|
||||
}
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* A wrapper for dealing with side-effect free functionality related to a loans
|
||||
* transactions and repayment schedule.
|
||||
*/
|
||||
@Component
|
||||
public final class LoanSummaryWrapper {
|
||||
|
||||
public Money calculateTotalPrincipalRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPrincipalCompleted(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPrincipalWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPrincipalWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPrincipalOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestCharged(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestCharged(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestPaid(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestWaived(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestWaived(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getInterestOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesCharged(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getFeeChargesCharged(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getFeeChargesPaid(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesWaived(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getFeeChargesWaived(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getFeeChargesWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getFeeChargesOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesCharged(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesCharged(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesPaid(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesWaived(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesWaived(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getPenaltyChargesOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
|
||||
final Money principalOverdue = calculateTotalPrincipalOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
final Money interestOverdue = calculateTotalInterestOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
final Money feeChargesOverdue = calculateTotalFeeChargesOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
final Money penaltyChargesOverdue = calculateTotalPenaltyChargesOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
|
||||
return principalOverdue.plus(interestOverdue).plus(feeChargesOverdue).plus(penaltyChargesOverdue);
|
||||
}
|
||||
|
||||
public LocalDate determineOverdueSinceDateFrom(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate from) {
|
||||
|
||||
LocalDate overdueSince = null;
|
||||
final Money totalOverdue = calculateTotalOverdueOn(repaymentScheduleInstallments, currency, from);
|
||||
if (totalOverdue.isGreaterThanZero()) {
|
||||
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(from)) {
|
||||
if (overdueSince == null || overdueSince.isAfter(installment.getDueDate())) {
|
||||
overdueSince = installment.getDueDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return overdueSince;
|
||||
}
|
||||
}
|
||||
+30
-249
@@ -14,131 +14,32 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
* Immutable data object to represent aspects of a loan schedule such as:
|
||||
*
|
||||
* <ul>
|
||||
* <li>summary information - the totals for each part of schedule monitored</li>
|
||||
* <li>repayment schedule - the principal due, outstanding balance and cost of
|
||||
* loan items such as interest and charges</li>
|
||||
* <li>Totals information - the totals for each part of repayment schedule
|
||||
* monitored.</li>
|
||||
* <li>Repayment schedule - the principal due, outstanding balance and cost of
|
||||
* loan items such as interest and charges (both fees and penalties)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LoanScheduleData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Integer loanTermInDays;
|
||||
|
||||
/**
|
||||
* The currency associated with all monetary values in loan schedule.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final CurrencyData currency;
|
||||
|
||||
/**
|
||||
* The cumulative total of all money (principal) disbursed to the loan
|
||||
* applicant.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePrincipalDisbursed;
|
||||
|
||||
/**
|
||||
* The cumulative total of all <code>principalDue</code> for each period of
|
||||
* loan schedule. (originalPrincipal)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePrincipalDue;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePrincipalPaid;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePrincipalWrittenOff;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePrincipalOutstanding;
|
||||
|
||||
/**
|
||||
* The cumulative total of interest expected on any principal disbursed.
|
||||
* (originalInterest)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeInterestExpected;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeInterestPaid;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeInterestWaived;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeInterestWrittenOff;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeInterestOutstanding;
|
||||
|
||||
/**
|
||||
* The cumulative total of all fee charges applied on the loan to date.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeFeeChargesToDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeFeeChargesPaid;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeFeeChargesWaived;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeFeeChargesWrittenOff;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeFeeChargesOutstanding;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePenaltyChargesToDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePenaltyChargesPaid;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePenaltyChargesWaived;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePenaltyChargesWrittenOff;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativePenaltyChargesOutstanding;
|
||||
|
||||
/**
|
||||
* The cumulative total of all costs on the loan. Costs tracked are:
|
||||
* <ul>
|
||||
* <li>Interest</li>
|
||||
* <li>Charges (fees and penalties)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalCostOfLoan;
|
||||
|
||||
/**
|
||||
* The sum of <code>principalDisbursed</code> and
|
||||
* <code>totalCostOfLoan</code>. (originalTotal)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalExpectedRepayment;
|
||||
|
||||
/**
|
||||
* The cumulative sum of all repayments to date. (totalPaid)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalPaidToDate;
|
||||
|
||||
/**
|
||||
* The cumulative sum of all waivers to date.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalWaivedToDate;
|
||||
|
||||
/**
|
||||
* The cumulative sum of all waivers to date.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalWrittenOffToDate;
|
||||
|
||||
/**
|
||||
* The cumulative sum of all principal, interest & charges outstanding.
|
||||
*/
|
||||
private final Integer loanTermInDays;
|
||||
private final BigDecimal totalPrincipalDisbursed;
|
||||
private final BigDecimal totalPrincipalExpected;
|
||||
private final BigDecimal totalPrincipalPaid;
|
||||
private final BigDecimal totalInterestCharged;
|
||||
private final BigDecimal totalFeeChargesCharged;
|
||||
private final BigDecimal totalPenaltyChargesCharged;
|
||||
private final BigDecimal totalWaived;
|
||||
private final BigDecimal totalWrittenOff;
|
||||
private final BigDecimal totalRepaymentExpected;
|
||||
private final BigDecimal totalRepayment;
|
||||
private final BigDecimal totalOutstanding;
|
||||
|
||||
/**
|
||||
* The amount by which this loan is is arrears.
|
||||
*
|
||||
* Different to outstanding as arrears is based on whether a portion of the
|
||||
* total outstanding is late and above any tolerance setting.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalInArrears;
|
||||
|
||||
/**
|
||||
* <code>periods</code> is collection of data objects containing specific
|
||||
* information to each period of the loan schedule including disbursement
|
||||
@@ -146,148 +47,28 @@ public class LoanScheduleData {
|
||||
*/
|
||||
private final Collection<LoanSchedulePeriodData> periods;
|
||||
|
||||
public LoanScheduleData() {
|
||||
this.cumulativePrincipalDisbursed = null;
|
||||
this.cumulativePrincipalPaid = null;
|
||||
this.cumulativePrincipalWrittenOff = null;
|
||||
this.cumulativePrincipalDue = null;
|
||||
this.cumulativePrincipalOutstanding = null;
|
||||
|
||||
this.cumulativeInterestExpected = null;
|
||||
this.cumulativeInterestPaid = null;
|
||||
this.cumulativeInterestWaived = null;
|
||||
this.cumulativeInterestWrittenOff = null;
|
||||
this.cumulativeInterestOutstanding = null;
|
||||
|
||||
this.cumulativeFeeChargesToDate = null;
|
||||
this.cumulativeFeeChargesPaid = null;
|
||||
this.cumulativeFeeChargesWaived = null;
|
||||
this.cumulativeFeeChargesWrittenOff = null;
|
||||
this.cumulativeFeeChargesOutstanding = null;
|
||||
|
||||
this.cumulativePenaltyChargesToDate = null;
|
||||
this.cumulativePenaltyChargesPaid = null;
|
||||
this.cumulativePenaltyChargesWaived = null;
|
||||
this.cumulativePenaltyChargesWrittenOff = null;
|
||||
this.cumulativePenaltyChargesOutstanding = null;
|
||||
|
||||
this.totalCostOfLoan = null;
|
||||
|
||||
this.totalExpectedRepayment = null;
|
||||
this.totalPaidToDate = null;
|
||||
this.totalWaivedToDate = null;
|
||||
this.totalWrittenOffToDate = null;
|
||||
this.totalOutstanding = null;
|
||||
this.totalInArrears = null;
|
||||
|
||||
this.currency = null;
|
||||
this.periods = null;
|
||||
this.loanTermInDays = null;
|
||||
}
|
||||
|
||||
public LoanScheduleData(final CurrencyData currency, final Collection<LoanSchedulePeriodData> periods, final Integer loanTermInDays,
|
||||
final BigDecimal cumulativePrincipalDisbursed, final BigDecimal cumulativePrincipalDue,
|
||||
final BigDecimal cumulativePrincipalOutstanding, final BigDecimal cumulativeInterestExpected,
|
||||
final BigDecimal cumulativeFeeChargesToDate, final BigDecimal totalExpectedRepayment) {
|
||||
final BigDecimal totalPrincipalDisbursed, final BigDecimal totalPrincipalExpected, final BigDecimal totalPrincipalPaid,
|
||||
final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged,
|
||||
final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalRepaymentExpected,
|
||||
final BigDecimal totalRepayment, final BigDecimal totalOutstanding) {
|
||||
this.currency = currency;
|
||||
this.periods = periods;
|
||||
this.loanTermInDays = loanTermInDays;
|
||||
|
||||
this.cumulativePrincipalDisbursed = cumulativePrincipalDisbursed;
|
||||
this.cumulativePrincipalDue = cumulativePrincipalDue;
|
||||
this.cumulativePrincipalPaid = null;
|
||||
this.cumulativePrincipalWrittenOff = null;
|
||||
this.cumulativePrincipalOutstanding = cumulativePrincipalOutstanding;
|
||||
|
||||
this.cumulativeInterestExpected = cumulativeInterestExpected;
|
||||
this.cumulativeInterestPaid = null;
|
||||
this.cumulativeInterestWaived = null;
|
||||
this.cumulativeInterestWrittenOff = null;
|
||||
this.cumulativeInterestOutstanding = null;
|
||||
|
||||
this.cumulativeFeeChargesToDate = cumulativeFeeChargesToDate;
|
||||
this.cumulativeFeeChargesPaid = null;
|
||||
this.cumulativeFeeChargesWaived = null;
|
||||
this.cumulativeFeeChargesWrittenOff = null;
|
||||
this.cumulativeFeeChargesOutstanding = null;
|
||||
|
||||
this.cumulativePenaltyChargesToDate = null;
|
||||
this.cumulativePenaltyChargesPaid = null;
|
||||
this.cumulativePenaltyChargesWaived = null;
|
||||
this.cumulativePenaltyChargesWrittenOff = null;
|
||||
this.cumulativePenaltyChargesOutstanding = null;
|
||||
|
||||
if (cumulativeFeeChargesToDate != null) {
|
||||
this.totalCostOfLoan = cumulativeInterestExpected.add(cumulativeFeeChargesToDate);
|
||||
} else if (cumulativeInterestExpected != null) {
|
||||
this.totalCostOfLoan = cumulativeInterestExpected;
|
||||
} else {
|
||||
this.totalCostOfLoan = null;
|
||||
}
|
||||
|
||||
this.totalExpectedRepayment = totalExpectedRepayment;
|
||||
this.totalPaidToDate = BigDecimal.ZERO;
|
||||
this.totalWaivedToDate = BigDecimal.ZERO;
|
||||
this.totalWrittenOffToDate = BigDecimal.ZERO;
|
||||
this.totalOutstanding = totalExpectedRepayment;
|
||||
this.totalInArrears = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used when fully populating
|
||||
*/
|
||||
public LoanScheduleData(final CurrencyData currency, final Collection<LoanSchedulePeriodData> periods, final Integer loanTermInDays,
|
||||
final BigDecimal cumulativePrincipalDisbursed, final BigDecimal cumulativePrincipalDue,
|
||||
final BigDecimal cumulativePrincipalPaid, final BigDecimal cumulativePrincipalWrittenOff,
|
||||
final BigDecimal cumulativePrincipalOutstanding, final BigDecimal cumulativeInterestExpected,
|
||||
final BigDecimal cumulativeInterestPaid, final BigDecimal cumulativeInterestWaived,
|
||||
final BigDecimal cumulativeInterestWrittenOff, final BigDecimal cumulativeInterestOutstanding,
|
||||
final BigDecimal cumulativeFeeChargesToDate, final BigDecimal cumulativeFeeChargesPaid,
|
||||
final BigDecimal cumulativeFeeChargesWaived, final BigDecimal cumulativeFeeChargesWrittenOff,
|
||||
final BigDecimal cumulativeFeeChargesOutstanding, final BigDecimal cumulativePenaltyChargesToDate,
|
||||
final BigDecimal cumulativePenaltyChargesPaid, final BigDecimal cumulativePenaltyChargesWaived,
|
||||
final BigDecimal cumulativePenaltyChargesWrittenOff, final BigDecimal cumulativePenaltyChargesOutstanding,
|
||||
final BigDecimal totalCostOfLoan, final BigDecimal totalExpectedRepayment, final BigDecimal totalPaidToDate,
|
||||
final BigDecimal totalWaivedToDate, final BigDecimal totalWrittenOffToDate, final BigDecimal totalOutstanding,
|
||||
final BigDecimal totalInArrears) {
|
||||
this.currency = currency;
|
||||
this.periods = periods;
|
||||
this.loanTermInDays = loanTermInDays;
|
||||
|
||||
this.cumulativePrincipalDisbursed = cumulativePrincipalDisbursed;
|
||||
this.cumulativePrincipalDue = cumulativePrincipalDue;
|
||||
this.cumulativePrincipalPaid = cumulativePrincipalPaid;
|
||||
this.cumulativePrincipalWrittenOff = cumulativePrincipalWrittenOff;
|
||||
this.cumulativePrincipalOutstanding = cumulativePrincipalOutstanding;
|
||||
this.cumulativeInterestExpected = cumulativeInterestExpected;
|
||||
this.cumulativeInterestPaid = cumulativeInterestPaid;
|
||||
this.cumulativeInterestWrittenOff = cumulativeInterestWrittenOff;
|
||||
this.cumulativeInterestWaived = cumulativeInterestWaived;
|
||||
this.cumulativeInterestOutstanding = cumulativeInterestOutstanding;
|
||||
this.cumulativeFeeChargesToDate = cumulativeFeeChargesToDate;
|
||||
this.cumulativeFeeChargesPaid = cumulativeFeeChargesPaid;
|
||||
this.cumulativeFeeChargesWaived = cumulativeFeeChargesWaived;
|
||||
this.cumulativeFeeChargesWrittenOff = cumulativeFeeChargesWrittenOff;
|
||||
this.cumulativeFeeChargesOutstanding = cumulativeFeeChargesOutstanding;
|
||||
this.cumulativePenaltyChargesToDate = cumulativePenaltyChargesToDate;
|
||||
this.cumulativePenaltyChargesPaid = cumulativePenaltyChargesPaid;
|
||||
this.cumulativePenaltyChargesWaived = cumulativePenaltyChargesWaived;
|
||||
this.cumulativePenaltyChargesWrittenOff = cumulativePenaltyChargesWrittenOff;
|
||||
this.cumulativePenaltyChargesOutstanding = cumulativePenaltyChargesOutstanding;
|
||||
this.totalCostOfLoan = totalCostOfLoan;
|
||||
this.totalExpectedRepayment = totalExpectedRepayment;
|
||||
this.totalPaidToDate = totalPaidToDate;
|
||||
this.totalWaivedToDate = totalWaivedToDate;
|
||||
this.totalWrittenOffToDate = totalWrittenOffToDate;
|
||||
this.totalPrincipalDisbursed = totalPrincipalDisbursed;
|
||||
this.totalPrincipalExpected = totalPrincipalExpected;
|
||||
this.totalPrincipalPaid = totalPrincipalPaid;
|
||||
this.totalInterestCharged = totalInterestCharged;
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
||||
this.totalWaived = totalWaived;
|
||||
this.totalWrittenOff = totalWrittenOff;
|
||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||
this.totalRepayment = totalRepayment;
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
this.totalInArrears = totalInArrears;
|
||||
}
|
||||
|
||||
public Collection<LoanSchedulePeriodData> getPeriods() {
|
||||
return periods;
|
||||
}
|
||||
|
||||
public BigDecimal totalOutstanding() {
|
||||
return this.totalOutstanding;
|
||||
}
|
||||
}
|
||||
+362
-420
@@ -16,439 +16,381 @@ import org.joda.time.LocalDate;
|
||||
*/
|
||||
public class LoanSchedulePeriodData {
|
||||
|
||||
private final Integer period;
|
||||
private final LocalDate fromDate;
|
||||
private final LocalDate dueDate;
|
||||
private final Integer daysInPeriod;
|
||||
private final BigDecimal principalDisbursed;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal principalOriginalDue;
|
||||
private final BigDecimal principalDue;
|
||||
private final BigDecimal principalPaid;
|
||||
private final BigDecimal principalWrittenOff;
|
||||
private final BigDecimal principalOutstanding;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal principalLoanBalanceOutstanding;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal interestOriginalDue;
|
||||
private final BigDecimal interestDue;
|
||||
private final BigDecimal interestPaid;
|
||||
private final BigDecimal interestWaived;
|
||||
private final BigDecimal interestWrittenOff;
|
||||
private final BigDecimal interestOutstanding;
|
||||
private final BigDecimal feeChargesDue;
|
||||
private final BigDecimal feeChargesPaid;
|
||||
private final BigDecimal feeChargesWaived;
|
||||
private final BigDecimal feeChargesWrittenOff;
|
||||
private final BigDecimal feeChargesOutstanding;
|
||||
private final BigDecimal penaltyChargesDue;
|
||||
private final BigDecimal penaltyChargesPaid;
|
||||
private final BigDecimal penaltyChargesWaived;
|
||||
private final BigDecimal penaltyChargesWrittenOff;
|
||||
private final BigDecimal penaltyChargesOutstanding;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalOriginalDueForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalDueForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalPaidForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalWaivedForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalWrittenOffForPeriod;
|
||||
private final BigDecimal totalOutstandingForPeriod;
|
||||
private final BigDecimal totalOverdue;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalActualCostOfLoanForPeriod;
|
||||
private final Integer period;
|
||||
private final LocalDate fromDate;
|
||||
private final LocalDate dueDate;
|
||||
private final Integer daysInPeriod;
|
||||
private final BigDecimal principalDisbursed;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal principalOriginalDue;
|
||||
private final BigDecimal principalDue;
|
||||
private final BigDecimal principalPaid;
|
||||
private final BigDecimal principalWrittenOff;
|
||||
private final BigDecimal principalOutstanding;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal principalLoanBalanceOutstanding;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal interestOriginalDue;
|
||||
private final BigDecimal interestDue;
|
||||
private final BigDecimal interestPaid;
|
||||
private final BigDecimal interestWaived;
|
||||
private final BigDecimal interestWrittenOff;
|
||||
private final BigDecimal interestOutstanding;
|
||||
private final BigDecimal feeChargesDue;
|
||||
private final BigDecimal feeChargesPaid;
|
||||
private final BigDecimal feeChargesWaived;
|
||||
private final BigDecimal feeChargesWrittenOff;
|
||||
private final BigDecimal feeChargesOutstanding;
|
||||
private final BigDecimal penaltyChargesDue;
|
||||
private final BigDecimal penaltyChargesPaid;
|
||||
private final BigDecimal penaltyChargesWaived;
|
||||
private final BigDecimal penaltyChargesWrittenOff;
|
||||
private final BigDecimal penaltyChargesOutstanding;
|
||||
|
||||
public static LoanSchedulePeriodData disbursementOnlyPeriod(
|
||||
final LocalDate disbursementDate,
|
||||
final BigDecimal principalDisbursed,
|
||||
final BigDecimal feeChargesDueAtTimeOfDisbursement,
|
||||
final boolean isDisbursed) {
|
||||
Integer periodNumber = Integer.valueOf(0);
|
||||
LocalDate from = null;
|
||||
return new LoanSchedulePeriodData(periodNumber, from, disbursementDate, principalDisbursed, feeChargesDueAtTimeOfDisbursement, isDisbursed);
|
||||
}
|
||||
|
||||
public static LoanSchedulePeriodData repaymentOnlyPeriod(
|
||||
final Integer periodNumber,
|
||||
final LocalDate fromDate,
|
||||
final LocalDate dueDate,
|
||||
final BigDecimal principalDue,
|
||||
final BigDecimal principalOutstanding,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal feeChargesDueForPeriod,
|
||||
final BigDecimal penaltyChargesDueForPeriod,
|
||||
final BigDecimal totalDueForPeriod) {
|
||||
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, principalDue, principalOutstanding,
|
||||
interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod, totalDueForPeriod);
|
||||
}
|
||||
|
||||
public static LoanSchedulePeriodData repaymentPeriodWithPayments(
|
||||
@SuppressWarnings("unused") final Long loanId,
|
||||
final Integer periodNumber,
|
||||
final LocalDate fromDate,
|
||||
final LocalDate dueDate,
|
||||
final BigDecimal principalOriginalDue,
|
||||
final BigDecimal principalPaid,
|
||||
final BigDecimal principalWrittenOff,
|
||||
final BigDecimal principalOutstanding,
|
||||
final BigDecimal outstandingPrincipalBalanceOfLoan,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal interestPaid,
|
||||
final BigDecimal interestWaived,
|
||||
final BigDecimal interestWrittenOff,
|
||||
final BigDecimal interestOutstanding,
|
||||
final BigDecimal feeChargesDue,
|
||||
final BigDecimal feeChargesPaid,
|
||||
final BigDecimal feeChargesWaived,
|
||||
final BigDecimal feeChargesWrittenOff,
|
||||
final BigDecimal feeChargesOutstanding,
|
||||
final BigDecimal penaltyChargesDue,
|
||||
final BigDecimal penaltyChargesPaid,
|
||||
final BigDecimal penaltyChargesWaived,
|
||||
final BigDecimal penaltyChargesWrittenOff,
|
||||
final BigDecimal penaltyChargesOutstanding,
|
||||
final BigDecimal totalDueForPeriod,
|
||||
final BigDecimal totalPaid,
|
||||
final BigDecimal totalWaived,
|
||||
final BigDecimal totalWrittenOff,
|
||||
final BigDecimal totalOutstanding,
|
||||
final BigDecimal totalActualCostOfLoanForPeriod) {
|
||||
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate,
|
||||
principalOriginalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan,
|
||||
interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestWrittenOff, interestOutstanding,
|
||||
feeChargesDue, feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding,
|
||||
penaltyChargesDue, penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding,
|
||||
totalDueForPeriod, totalPaid, totalWaived, totalWrittenOff, totalOutstanding, totalActualCostOfLoanForPeriod);
|
||||
}
|
||||
|
||||
/*
|
||||
* constructor used for creating period on loan schedule that is only a disbursement (typically first period)
|
||||
*/
|
||||
private LoanSchedulePeriodData(
|
||||
final Integer periodNumber,
|
||||
final LocalDate fromDate,
|
||||
final LocalDate dueDate,
|
||||
final BigDecimal principalDisbursed,
|
||||
final BigDecimal chargesDueAtTimeOfDisbursement,
|
||||
final boolean isDisbursed) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = principalDisbursed;
|
||||
this.principalOriginalDue = null;
|
||||
this.principalDue = null;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = null;
|
||||
this.principalLoanBalanceOutstanding = principalDisbursed;
|
||||
|
||||
this.interestOriginalDue = null;
|
||||
this.interestDue = null;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = null;
|
||||
|
||||
this.feeChargesDue = chargesDueAtTimeOfDisbursement;
|
||||
if (isDisbursed) {
|
||||
this.feeChargesPaid = chargesDueAtTimeOfDisbursement;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = null;
|
||||
} else {
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = chargesDueAtTimeOfDisbursement;
|
||||
}
|
||||
|
||||
this.penaltyChargesDue = null;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
this.penaltyChargesOutstanding = null;
|
||||
|
||||
this.totalOriginalDueForPeriod = chargesDueAtTimeOfDisbursement;
|
||||
this.totalDueForPeriod = chargesDueAtTimeOfDisbursement;
|
||||
this.totalPaidForPeriod = this.feeChargesPaid;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = this.feeChargesOutstanding;
|
||||
this.totalActualCostOfLoanForPeriod = this.feeChargesDue;
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
}
|
||||
|
||||
private LoanSchedulePeriodData(
|
||||
final Integer periodNumber,
|
||||
final LocalDate fromDate,
|
||||
final LocalDate dueDate,
|
||||
final BigDecimal principalOriginalDue,
|
||||
final BigDecimal principalOutstanding,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal feeChargesDueForPeriod,
|
||||
final BigDecimal penaltyChargesDueForPeriod,
|
||||
final BigDecimal totalDueForPeriod) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = null;
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = principalOriginalDue;
|
||||
this.principalLoanBalanceOutstanding = principalOutstanding;
|
||||
|
||||
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = interestDueOnPrincipalOutstanding;
|
||||
|
||||
this.feeChargesDue = feeChargesDueForPeriod;
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = null;
|
||||
|
||||
this.penaltyChargesDue = penaltyChargesDueForPeriod;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
this.penaltyChargesOutstanding = null;
|
||||
|
||||
this.totalOriginalDueForPeriod = totalDueForPeriod;
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = BigDecimal.ZERO;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = totalDueForPeriod;
|
||||
this.totalActualCostOfLoanForPeriod = interestDueOnPrincipalOutstanding.add(feeChargesDueForPeriod);
|
||||
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used for creating loan schedule periods with full information on expected principal, interest & charges along with what portion of each is paid.
|
||||
*/
|
||||
private LoanSchedulePeriodData(
|
||||
final Integer periodNumber,
|
||||
final LocalDate fromDate,
|
||||
final LocalDate dueDate,
|
||||
final BigDecimal principalOriginalDue,
|
||||
final BigDecimal principalPaid,
|
||||
final BigDecimal principalWrittenOff,
|
||||
final BigDecimal principalOutstanding,
|
||||
final BigDecimal principalLoanBalanceOutstanding,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal interestPaid,
|
||||
final BigDecimal interestWaived,
|
||||
final BigDecimal interestWrittenOff,
|
||||
final BigDecimal interestOutstanding,
|
||||
final BigDecimal feeChargesDue,
|
||||
final BigDecimal feeChargesPaid,
|
||||
final BigDecimal feeChargesWaived,
|
||||
final BigDecimal feeChargesWrittenOff,
|
||||
final BigDecimal feeChargesOutstanding,
|
||||
final BigDecimal penaltyChargesDue,
|
||||
final BigDecimal penaltyChargesPaid,
|
||||
final BigDecimal penaltyChargesWaived,
|
||||
final BigDecimal penaltyChargesWrittenOff,
|
||||
final BigDecimal penaltyChargesOutstanding,
|
||||
final BigDecimal totalDueForPeriod,
|
||||
final BigDecimal totalPaid,
|
||||
final BigDecimal totalWaived,
|
||||
final BigDecimal totalWrittenOff,
|
||||
final BigDecimal totalOutstanding,
|
||||
final BigDecimal totalActualCostOfLoanForPeriod) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = null;
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = principalPaid;
|
||||
this.principalWrittenOff = principalWrittenOff;
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
this.principalLoanBalanceOutstanding = principalLoanBalanceOutstanding;
|
||||
|
||||
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = interestPaid;
|
||||
this.interestWaived = interestWaived;
|
||||
this.interestWrittenOff = interestWrittenOff;
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
|
||||
this.feeChargesDue = feeChargesDue;
|
||||
this.feeChargesPaid = feeChargesPaid;
|
||||
this.feeChargesWaived = feeChargesWaived;
|
||||
this.feeChargesWrittenOff = feeChargesWrittenOff;
|
||||
this.feeChargesOutstanding = feeChargesOutstanding;
|
||||
|
||||
this.penaltyChargesDue = penaltyChargesDue;
|
||||
this.penaltyChargesPaid = penaltyChargesPaid;
|
||||
this.penaltyChargesWaived = penaltyChargesWaived;
|
||||
this.penaltyChargesWrittenOff = penaltyChargesWrittenOff;
|
||||
this.penaltyChargesOutstanding = penaltyChargesOutstanding;
|
||||
|
||||
this.totalOriginalDueForPeriod = totalDueForPeriod;
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = totalPaid;
|
||||
this.totalWaivedForPeriod = totalWaived;
|
||||
this.totalWrittenOffForPeriod = totalWrittenOff;
|
||||
this.totalOutstandingForPeriod = totalOutstanding;
|
||||
this.totalActualCostOfLoanForPeriod = totalActualCostOfLoanForPeriod;
|
||||
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal defaultToZeroIfNull(final BigDecimal possibleNullValue) {
|
||||
BigDecimal value = BigDecimal.ZERO;
|
||||
if (possibleNullValue != null) {
|
||||
value = possibleNullValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalOriginalDueForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalDueForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalPaidForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalWaivedForPeriod;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalWrittenOffForPeriod;
|
||||
private final BigDecimal totalOutstandingForPeriod;
|
||||
private final BigDecimal totalOverdue;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal totalActualCostOfLoanForPeriod;
|
||||
|
||||
public boolean isRepaymentPeriod() {
|
||||
boolean isRepaymentPeriod = false;
|
||||
if (principalDue != null && this.interestDue != null) {
|
||||
isRepaymentPeriod = BigDecimal.ZERO.compareTo(this.principalDue) == -1 || BigDecimal.ZERO.compareTo(this.interestDue) == -1;
|
||||
}
|
||||
return isRepaymentPeriod;
|
||||
}
|
||||
public static LoanSchedulePeriodData disbursementOnlyPeriod(final LocalDate disbursementDate, final BigDecimal principalDisbursed,
|
||||
final BigDecimal feeChargesDueAtTimeOfDisbursement, final boolean isDisbursed) {
|
||||
Integer periodNumber = Integer.valueOf(0);
|
||||
LocalDate from = null;
|
||||
return new LoanSchedulePeriodData(periodNumber, from, disbursementDate, principalDisbursed, feeChargesDueAtTimeOfDisbursement,
|
||||
isDisbursed);
|
||||
}
|
||||
|
||||
public Integer periodNumber() {
|
||||
return this.period;
|
||||
}
|
||||
public static LoanSchedulePeriodData repaymentOnlyPeriod(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final BigDecimal principalDue, final BigDecimal principalOutstanding, final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal feeChargesDueForPeriod, final BigDecimal penaltyChargesDueForPeriod, final BigDecimal totalDueForPeriod) {
|
||||
|
||||
public LocalDate periodFromDate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
|
||||
public LocalDate periodDueDate() {
|
||||
return this.dueDate;
|
||||
}
|
||||
|
||||
public Integer daysInPeriod() {
|
||||
return this.daysInPeriod;
|
||||
}
|
||||
|
||||
public BigDecimal principalDisbursed() {
|
||||
return defaultToZeroIfNull(this.principalDisbursed);
|
||||
}
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, principalDue, principalOutstanding,
|
||||
interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod, totalDueForPeriod);
|
||||
}
|
||||
|
||||
public BigDecimal principalDue() {
|
||||
return defaultToZeroIfNull(this.principalDue);
|
||||
}
|
||||
public static LoanSchedulePeriodData repaymentPeriodWithPayments(@SuppressWarnings("unused") final Long loanId,
|
||||
final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principalOriginalDue,
|
||||
final BigDecimal principalPaid, final BigDecimal principalWrittenOff, final BigDecimal principalOutstanding,
|
||||
final BigDecimal outstandingPrincipalBalanceOfLoan, final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWrittenOff,
|
||||
final BigDecimal interestOutstanding, final BigDecimal feeChargesDue, final BigDecimal feeChargesPaid,
|
||||
final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff, final BigDecimal feeChargesOutstanding,
|
||||
final BigDecimal penaltyChargesDue, final BigDecimal penaltyChargesPaid, final BigDecimal penaltyChargesWaived,
|
||||
final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesOutstanding, final BigDecimal totalDueForPeriod,
|
||||
final BigDecimal totalPaid, final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalOutstanding,
|
||||
final BigDecimal totalActualCostOfLoanForPeriod) {
|
||||
|
||||
public BigDecimal principalPaid() {
|
||||
return defaultToZeroIfNull(this.principalPaid);
|
||||
}
|
||||
|
||||
public BigDecimal principalWrittenOff() {
|
||||
return defaultToZeroIfNull(this.principalWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal principalOutstanding() {
|
||||
return defaultToZeroIfNull(this.principalOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal interestDue() {
|
||||
return defaultToZeroIfNull(this.interestDue);
|
||||
}
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, principalOriginalDue, principalPaid, principalWrittenOff,
|
||||
principalOutstanding, outstandingPrincipalBalanceOfLoan, interestDueOnPrincipalOutstanding, interestPaid, interestWaived,
|
||||
interestWrittenOff, interestOutstanding, feeChargesDue, feeChargesPaid, feeChargesWaived, feeChargesWrittenOff,
|
||||
feeChargesOutstanding, penaltyChargesDue, penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff,
|
||||
penaltyChargesOutstanding, totalDueForPeriod, totalPaid, totalWaived, totalWrittenOff, totalOutstanding,
|
||||
totalActualCostOfLoanForPeriod);
|
||||
}
|
||||
|
||||
public BigDecimal interestPaid() {
|
||||
return defaultToZeroIfNull(this.interestPaid);
|
||||
}
|
||||
/*
|
||||
* constructor used for creating period on loan schedule that is only a
|
||||
* disbursement (typically first period)
|
||||
*/
|
||||
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final BigDecimal principalDisbursed, final BigDecimal chargesDueAtTimeOfDisbursement, final boolean isDisbursed) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = principalDisbursed;
|
||||
this.principalOriginalDue = null;
|
||||
this.principalDue = null;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = null;
|
||||
this.principalLoanBalanceOutstanding = principalDisbursed;
|
||||
|
||||
public BigDecimal interestWaived() {
|
||||
return defaultToZeroIfNull(this.interestWaived);
|
||||
}
|
||||
|
||||
public BigDecimal interestWrittenOff() {
|
||||
return defaultToZeroIfNull(this.interestWrittenOff);
|
||||
}
|
||||
this.interestOriginalDue = null;
|
||||
this.interestDue = null;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = null;
|
||||
|
||||
public BigDecimal interestOutstanding() {
|
||||
return defaultToZeroIfNull(this.interestOutstanding);
|
||||
}
|
||||
this.feeChargesDue = chargesDueAtTimeOfDisbursement;
|
||||
if (isDisbursed) {
|
||||
this.feeChargesPaid = chargesDueAtTimeOfDisbursement;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = null;
|
||||
} else {
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = chargesDueAtTimeOfDisbursement;
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesDue() {
|
||||
return defaultToZeroIfNull(this.feeChargesDue);
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesWaived() {
|
||||
return defaultToZeroIfNull(this.feeChargesWaived);
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesWrittenOff() {
|
||||
return defaultToZeroIfNull(this.feeChargesWrittenOff);
|
||||
}
|
||||
this.penaltyChargesDue = null;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
this.penaltyChargesOutstanding = null;
|
||||
|
||||
public BigDecimal feeChargesPaid() {
|
||||
return defaultToZeroIfNull(this.feeChargesPaid);
|
||||
}
|
||||
this.totalOriginalDueForPeriod = chargesDueAtTimeOfDisbursement;
|
||||
this.totalDueForPeriod = chargesDueAtTimeOfDisbursement;
|
||||
this.totalPaidForPeriod = this.feeChargesPaid;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = this.feeChargesOutstanding;
|
||||
this.totalActualCostOfLoanForPeriod = this.feeChargesDue;
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesOutstanding() {
|
||||
return defaultToZeroIfNull(this.feeChargesOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesDue() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesDue);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesWaived() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesWaived);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesWrittenOff() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesWrittenOff);
|
||||
}
|
||||
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final BigDecimal principalOriginalDue, final BigDecimal principalOutstanding,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal feeChargesDueForPeriod,
|
||||
final BigDecimal penaltyChargesDueForPeriod, final BigDecimal totalDueForPeriod) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = null;
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = principalOriginalDue;
|
||||
this.principalLoanBalanceOutstanding = principalOutstanding;
|
||||
|
||||
public BigDecimal penaltyChargesPaid() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesPaid);
|
||||
}
|
||||
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = interestDueOnPrincipalOutstanding;
|
||||
|
||||
public BigDecimal penaltyChargesOutstanding() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesOutstanding);
|
||||
}
|
||||
this.feeChargesDue = feeChargesDueForPeriod;
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = null;
|
||||
|
||||
public BigDecimal totalOverdue() {
|
||||
return defaultToZeroIfNull(this.totalOverdue);
|
||||
}
|
||||
this.penaltyChargesDue = penaltyChargesDueForPeriod;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
this.penaltyChargesOutstanding = null;
|
||||
|
||||
this.totalOriginalDueForPeriod = totalDueForPeriod;
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = BigDecimal.ZERO;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = totalDueForPeriod;
|
||||
this.totalActualCostOfLoanForPeriod = interestDueOnPrincipalOutstanding.add(feeChargesDueForPeriod);
|
||||
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used for creating loan schedule periods with full information on expected
|
||||
* principal, interest & charges along with what portion of each is paid.
|
||||
*/
|
||||
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final BigDecimal principalOriginalDue, final BigDecimal principalPaid, final BigDecimal principalWrittenOff,
|
||||
final BigDecimal principalOutstanding, final BigDecimal principalLoanBalanceOutstanding,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal interestPaid, final BigDecimal interestWaived,
|
||||
final BigDecimal interestWrittenOff, final BigDecimal interestOutstanding, final BigDecimal feeChargesDue,
|
||||
final BigDecimal feeChargesPaid, final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff,
|
||||
final BigDecimal feeChargesOutstanding, final BigDecimal penaltyChargesDue, final BigDecimal penaltyChargesPaid,
|
||||
final BigDecimal penaltyChargesWaived, final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesOutstanding,
|
||||
final BigDecimal totalDueForPeriod, final BigDecimal totalPaid, final BigDecimal totalWaived, final BigDecimal totalWrittenOff,
|
||||
final BigDecimal totalOutstanding, final BigDecimal totalActualCostOfLoanForPeriod) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = null;
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = principalPaid;
|
||||
this.principalWrittenOff = principalWrittenOff;
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
this.principalLoanBalanceOutstanding = principalLoanBalanceOutstanding;
|
||||
|
||||
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = interestPaid;
|
||||
this.interestWaived = interestWaived;
|
||||
this.interestWrittenOff = interestWrittenOff;
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
|
||||
this.feeChargesDue = feeChargesDue;
|
||||
this.feeChargesPaid = feeChargesPaid;
|
||||
this.feeChargesWaived = feeChargesWaived;
|
||||
this.feeChargesWrittenOff = feeChargesWrittenOff;
|
||||
this.feeChargesOutstanding = feeChargesOutstanding;
|
||||
|
||||
this.penaltyChargesDue = penaltyChargesDue;
|
||||
this.penaltyChargesPaid = penaltyChargesPaid;
|
||||
this.penaltyChargesWaived = penaltyChargesWaived;
|
||||
this.penaltyChargesWrittenOff = penaltyChargesWrittenOff;
|
||||
this.penaltyChargesOutstanding = penaltyChargesOutstanding;
|
||||
|
||||
this.totalOriginalDueForPeriod = totalDueForPeriod;
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = totalPaid;
|
||||
this.totalWaivedForPeriod = totalWaived;
|
||||
this.totalWrittenOffForPeriod = totalWrittenOff;
|
||||
this.totalOutstandingForPeriod = totalOutstanding;
|
||||
this.totalActualCostOfLoanForPeriod = totalActualCostOfLoanForPeriod;
|
||||
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal defaultToZeroIfNull(final BigDecimal possibleNullValue) {
|
||||
BigDecimal value = BigDecimal.ZERO;
|
||||
if (possibleNullValue != null) {
|
||||
value = possibleNullValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean isRepaymentPeriod() {
|
||||
boolean isRepaymentPeriod = false;
|
||||
if (principalDue != null && this.interestDue != null) {
|
||||
isRepaymentPeriod = BigDecimal.ZERO.compareTo(this.principalDue) == -1 || BigDecimal.ZERO.compareTo(this.interestDue) == -1;
|
||||
}
|
||||
return isRepaymentPeriod;
|
||||
}
|
||||
|
||||
public Integer periodNumber() {
|
||||
return this.period;
|
||||
}
|
||||
|
||||
public LocalDate periodFromDate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
|
||||
public LocalDate periodDueDate() {
|
||||
return this.dueDate;
|
||||
}
|
||||
|
||||
public Integer daysInPeriod() {
|
||||
return this.daysInPeriod;
|
||||
}
|
||||
|
||||
public BigDecimal principalDisbursed() {
|
||||
return defaultToZeroIfNull(this.principalDisbursed);
|
||||
}
|
||||
|
||||
public BigDecimal principalDue() {
|
||||
return defaultToZeroIfNull(this.principalDue);
|
||||
}
|
||||
|
||||
public BigDecimal principalPaid() {
|
||||
return defaultToZeroIfNull(this.principalPaid);
|
||||
}
|
||||
|
||||
public BigDecimal principalWrittenOff() {
|
||||
return defaultToZeroIfNull(this.principalWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal principalOutstanding() {
|
||||
return defaultToZeroIfNull(this.principalOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal interestDue() {
|
||||
return defaultToZeroIfNull(this.interestDue);
|
||||
}
|
||||
|
||||
public BigDecimal interestPaid() {
|
||||
return defaultToZeroIfNull(this.interestPaid);
|
||||
}
|
||||
|
||||
public BigDecimal interestWaived() {
|
||||
return defaultToZeroIfNull(this.interestWaived);
|
||||
}
|
||||
|
||||
public BigDecimal interestWrittenOff() {
|
||||
return defaultToZeroIfNull(this.interestWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal interestOutstanding() {
|
||||
return defaultToZeroIfNull(this.interestOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesDue() {
|
||||
return defaultToZeroIfNull(this.feeChargesDue);
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesWaived() {
|
||||
return defaultToZeroIfNull(this.feeChargesWaived);
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesWrittenOff() {
|
||||
return defaultToZeroIfNull(this.feeChargesWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesPaid() {
|
||||
return defaultToZeroIfNull(this.feeChargesPaid);
|
||||
}
|
||||
|
||||
public BigDecimal feeChargesOutstanding() {
|
||||
return defaultToZeroIfNull(this.feeChargesOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesDue() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesDue);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesWaived() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesWaived);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesWrittenOff() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesPaid() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesPaid);
|
||||
}
|
||||
|
||||
public BigDecimal penaltyChargesOutstanding() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal totalOverdue() {
|
||||
return defaultToZeroIfNull(this.totalOverdue);
|
||||
}
|
||||
}
|
||||
+19
-13
@@ -70,10 +70,17 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
|
||||
periods.add(disbursementPeriod);
|
||||
|
||||
int loanTermInDays = Integer.valueOf(0);
|
||||
BigDecimal cumulativePrincipalDisbursed = loanScheduleInfo.getPrincipal().getAmount();
|
||||
BigDecimal cumulativePrincipalDue = BigDecimal.ZERO;
|
||||
BigDecimal cumulativeInterestExpected = BigDecimal.ZERO;
|
||||
BigDecimal totalExpectedRepayment = chargesDueAtTimeOfDisbursement;
|
||||
BigDecimal totalPrincipalDisbursed = principalDisbursed.getAmount();
|
||||
BigDecimal totalPrincipalExpected = BigDecimal.ZERO;
|
||||
BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
|
||||
BigDecimal totalInterestCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalFeeChargesCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalPenaltyChargesCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalWaived = BigDecimal.ZERO;
|
||||
BigDecimal totalWrittenOff = BigDecimal.ZERO;
|
||||
BigDecimal totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
|
||||
BigDecimal totalRepayment = BigDecimal.ZERO;
|
||||
BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||
|
||||
LocalDate startDate = disbursementDate;
|
||||
int periodNumber = 1;
|
||||
@@ -138,21 +145,20 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
|
||||
|
||||
// handle cumulative fields
|
||||
loanTermInDays += daysInPeriod;
|
||||
cumulativePrincipalDue = cumulativePrincipalDue.add(principalForInstallment.getAmount());
|
||||
cumulativeInterestExpected = cumulativeInterestExpected.add(interestForInstallment.getAmount());
|
||||
totalExpectedRepayment = totalExpectedRepayment.add(totalInstallmentDue.getAmount());
|
||||
totalPrincipalExpected = totalPrincipalExpected.add(principalForInstallment.getAmount());
|
||||
totalInterestCharged = totalInterestCharged.add(interestForInstallment.getAmount());
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(totalInstallmentDue.getAmount());
|
||||
startDate = scheduledDueDate;
|
||||
|
||||
periodNumber++;
|
||||
}
|
||||
|
||||
final BigDecimal cumulativePrincipalOutstanding = cumulativePrincipalDisbursed.subtract(cumulativePrincipalDue);
|
||||
final CurrencyData currencyData = new CurrencyData(currency.getCode(), currency.getName(),
|
||||
monetaryCurrency.getDigitsAfterDecimal(), currency.getDisplaySymbol(), currency.getNameCode());
|
||||
|
||||
CurrencyData currencyData = new CurrencyData(currency.getCode(), currency.getName(), monetaryCurrency.getDigitsAfterDecimal(),
|
||||
currency.getDisplaySymbol(), currency.getNameCode());
|
||||
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, totalPrincipalDisbursed, totalPrincipalExpected,
|
||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalWaived, totalWrittenOff,
|
||||
totalRepaymentExpected, totalRepayment, totalOutstanding);
|
||||
}
|
||||
|
||||
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
|
||||
|
||||
+115
-113
@@ -24,123 +24,125 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
|
||||
public class EqualPrincipalAmortizationLoanScheduleGenerator implements AmortizationLoanScheduleGenerator {
|
||||
|
||||
private final PeriodicInterestRateCalculator periodicInterestRateCalculator = new PeriodicInterestRateCalculator();
|
||||
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
|
||||
|
||||
@Override
|
||||
public LoanScheduleData generate(
|
||||
final ApplicationCurrency currency,
|
||||
final LoanProductRelatedDetail loanScheduleInfo,
|
||||
final LocalDate disbursementDate,
|
||||
final LocalDate interestCalculatedFrom,
|
||||
final BigDecimal periodInterestRateForRepaymentPeriod,
|
||||
final LocalDate idealDisbursementDateBasedOnFirstRepaymentDate,
|
||||
final List<LocalDate> scheduledDates,
|
||||
final Set<LoanCharge> loanCharges) {
|
||||
private final PeriodicInterestRateCalculator periodicInterestRateCalculator = new PeriodicInterestRateCalculator();
|
||||
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
|
||||
|
||||
final Collection<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>();
|
||||
|
||||
// 1. we know 'principal' must be equal over repayments so use this to calculate interest and thus total repayment due.
|
||||
final MonetaryCurrency monetaryCurrency = loanScheduleInfo.getPrincipal().getCurrency();
|
||||
Money totalDuePerInstallment = Money.zero(monetaryCurrency);
|
||||
@Override
|
||||
public LoanScheduleData generate(final ApplicationCurrency currency, final LoanProductRelatedDetail loanScheduleInfo,
|
||||
final LocalDate disbursementDate, final LocalDate interestCalculatedFrom,
|
||||
final BigDecimal periodInterestRateForRepaymentPeriod, final LocalDate idealDisbursementDateBasedOnFirstRepaymentDate,
|
||||
final List<LocalDate> scheduledDates, final Set<LoanCharge> loanCharges) {
|
||||
|
||||
Money outstandingBalance = loanScheduleInfo.getPrincipal();
|
||||
Money principalDisbursed = loanScheduleInfo.getPrincipal();
|
||||
Money totalPrincipal = Money.zero(monetaryCurrency);
|
||||
Money totalInterest = Money.zero(monetaryCurrency);
|
||||
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator.calculateRepaymentPeriodAsAFractionOfDays(loanScheduleInfo.getRepaymentPeriodFrequencyType(),
|
||||
loanScheduleInfo.getRepayEvery(), interestCalculatedFrom, scheduledDates, idealDisbursementDateBasedOnFirstRepaymentDate);
|
||||
|
||||
BigDecimal chargesDueAtTimeOfDisbursement = BigDecimal.ZERO;
|
||||
for (LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isDueAtDisbursement()) {
|
||||
chargesDueAtTimeOfDisbursement = chargesDueAtTimeOfDisbursement.add(loanCharge.amount());
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal cumulativeChargesToDate = chargesDueAtTimeOfDisbursement;
|
||||
|
||||
// create entries of disbursement period on loan schedule
|
||||
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement, false);
|
||||
periods.add(disbursementPeriod);
|
||||
|
||||
int loanTermInDays = Integer.valueOf(0);
|
||||
BigDecimal cumulativePrincipalDisbursed = principalDisbursed.getAmount();
|
||||
BigDecimal cumulativePrincipalDue = BigDecimal.ZERO;
|
||||
BigDecimal cumulativeInterestExpected = BigDecimal.ZERO;
|
||||
BigDecimal totalExpectedRepayment = chargesDueAtTimeOfDisbursement;
|
||||
|
||||
LocalDate startDate = disbursementDate;
|
||||
int periodNumber = 1;
|
||||
for (LocalDate scheduledDueDate : scheduledDates) {
|
||||
final Collection<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>();
|
||||
|
||||
// number of days from startDate to this scheduledDate
|
||||
int daysInPeriod = Days.daysBetween(startDate.toDateMidnight().toDateTime(), scheduledDueDate.toDateMidnight().toDateTime()).getDays();
|
||||
|
||||
Money interestForInstallment = this.periodicInterestRateCalculator.calculateInterestOn(outstandingBalance, periodInterestRateForRepaymentPeriod, daysInPeriod, loanScheduleInfo);
|
||||
Money principalForInstallment = this.periodicInterestRateCalculator.calculatePrincipalOn(totalDuePerInstallment, interestForInstallment, loanScheduleInfo);
|
||||
|
||||
if (interestCalculationGraceOnRepaymentPeriodFraction >= Integer.valueOf(1).doubleValue()) {
|
||||
Money graceOnInterestForRepaymentPeriod = interestForInstallment;
|
||||
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
|
||||
interestCalculationGraceOnRepaymentPeriodFraction = interestCalculationGraceOnRepaymentPeriodFraction - Integer.valueOf(1).doubleValue();
|
||||
} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25") && interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) {
|
||||
Money graceOnInterestForRepaymentPeriod = interestForInstallment.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
|
||||
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
|
||||
interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf("0");
|
||||
}
|
||||
|
||||
totalPrincipal = totalPrincipal.plus(principalForInstallment);
|
||||
totalInterest = totalInterest.plus(interestForInstallment);
|
||||
|
||||
if (periodNumber == loanScheduleInfo.getNumberOfRepayments()) {
|
||||
Money principalDifference = totalPrincipal.minus(loanScheduleInfo.getPrincipal());
|
||||
if (principalDifference.isLessThanZero()) {
|
||||
principalForInstallment = principalForInstallment.plus(principalDifference.abs());
|
||||
} else if (principalDifference.isGreaterThanZero()) {
|
||||
principalForInstallment = principalForInstallment.minus(principalDifference.abs());
|
||||
}
|
||||
}
|
||||
// 1. we know 'principal' must be equal over repayments so use this to
|
||||
// calculate interest and thus total repayment due.
|
||||
final MonetaryCurrency monetaryCurrency = loanScheduleInfo.getPrincipal().getCurrency();
|
||||
Money totalDuePerInstallment = Money.zero(monetaryCurrency);
|
||||
|
||||
outstandingBalance = outstandingBalance.minus(principalForInstallment);
|
||||
|
||||
Money feeChargesForInstallment = Money.zero(monetaryCurrency);
|
||||
Money penaltyChargesForInstallment = Money.zero(monetaryCurrency);
|
||||
Money totalInstallmentDue = principalForInstallment.plus(interestForInstallment).plus(feeChargesForInstallment);
|
||||
cumulativeChargesToDate = cumulativeChargesToDate.add(feeChargesForInstallment.getAmount());
|
||||
|
||||
LoanSchedulePeriodData installment = LoanSchedulePeriodData.repaymentOnlyPeriod(periodNumber, startDate,
|
||||
scheduledDueDate,
|
||||
principalForInstallment.getAmount(),
|
||||
outstandingBalance.getAmount(),
|
||||
interestForInstallment.getAmount(),
|
||||
feeChargesForInstallment.getAmount(),
|
||||
penaltyChargesForInstallment.getAmount(),
|
||||
totalInstallmentDue.getAmount());
|
||||
Money outstandingBalance = loanScheduleInfo.getPrincipal();
|
||||
Money principalDisbursed = loanScheduleInfo.getPrincipal();
|
||||
Money totalPrincipal = Money.zero(monetaryCurrency);
|
||||
Money totalInterest = Money.zero(monetaryCurrency);
|
||||
|
||||
periods.add(installment);
|
||||
|
||||
// handle cumulative fields
|
||||
loanTermInDays += daysInPeriod;
|
||||
cumulativePrincipalDue = cumulativePrincipalDue.add(principalForInstallment.getAmount());
|
||||
cumulativeInterestExpected = cumulativeInterestExpected.add(interestForInstallment.getAmount());
|
||||
totalExpectedRepayment = totalExpectedRepayment.add(totalInstallmentDue.getAmount());
|
||||
startDate = scheduledDueDate;
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
|
||||
.calculateRepaymentPeriodAsAFractionOfDays(loanScheduleInfo.getRepaymentPeriodFrequencyType(),
|
||||
loanScheduleInfo.getRepayEvery(), interestCalculatedFrom, scheduledDates,
|
||||
idealDisbursementDateBasedOnFirstRepaymentDate);
|
||||
|
||||
periodNumber++;
|
||||
}
|
||||
|
||||
final BigDecimal cumulativePrincipalOutstanding = cumulativePrincipalDisbursed.subtract(cumulativePrincipalDue);
|
||||
|
||||
CurrencyData currencyData = new CurrencyData(
|
||||
currency.getCode(),
|
||||
currency.getName(),
|
||||
monetaryCurrency.getDigitsAfterDecimal(),
|
||||
currency.getDisplaySymbol(),
|
||||
currency.getNameCode());
|
||||
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
|
||||
}
|
||||
BigDecimal chargesDueAtTimeOfDisbursement = BigDecimal.ZERO;
|
||||
for (LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isDueAtDisbursement()) {
|
||||
chargesDueAtTimeOfDisbursement = chargesDueAtTimeOfDisbursement.add(loanCharge.amount());
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal cumulativeChargesToDate = chargesDueAtTimeOfDisbursement;
|
||||
|
||||
// create entries of disbursement period on loan schedule
|
||||
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate,
|
||||
principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement, false);
|
||||
periods.add(disbursementPeriod);
|
||||
|
||||
int loanTermInDays = Integer.valueOf(0);
|
||||
BigDecimal totalPrincipalDisbursed = principalDisbursed.getAmount();
|
||||
BigDecimal totalPrincipalExpected = BigDecimal.ZERO;
|
||||
BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
|
||||
BigDecimal totalInterestCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalFeeChargesCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalPenaltyChargesCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalWaived = BigDecimal.ZERO;
|
||||
BigDecimal totalWrittenOff = BigDecimal.ZERO;
|
||||
BigDecimal totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
|
||||
BigDecimal totalRepayment = BigDecimal.ZERO;
|
||||
BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||
|
||||
LocalDate startDate = disbursementDate;
|
||||
int periodNumber = 1;
|
||||
for (LocalDate scheduledDueDate : scheduledDates) {
|
||||
|
||||
// number of days from startDate to this scheduledDate
|
||||
int daysInPeriod = Days.daysBetween(startDate.toDateMidnight().toDateTime(), scheduledDueDate.toDateMidnight().toDateTime())
|
||||
.getDays();
|
||||
|
||||
Money interestForInstallment = this.periodicInterestRateCalculator.calculateInterestOn(outstandingBalance,
|
||||
periodInterestRateForRepaymentPeriod, daysInPeriod, loanScheduleInfo);
|
||||
Money principalForInstallment = this.periodicInterestRateCalculator.calculatePrincipalOn(totalDuePerInstallment,
|
||||
interestForInstallment, loanScheduleInfo);
|
||||
|
||||
if (interestCalculationGraceOnRepaymentPeriodFraction >= Integer.valueOf(1).doubleValue()) {
|
||||
Money graceOnInterestForRepaymentPeriod = interestForInstallment;
|
||||
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
|
||||
interestCalculationGraceOnRepaymentPeriodFraction = interestCalculationGraceOnRepaymentPeriodFraction
|
||||
- Integer.valueOf(1).doubleValue();
|
||||
} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25")
|
||||
&& interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) {
|
||||
Money graceOnInterestForRepaymentPeriod = interestForInstallment
|
||||
.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
|
||||
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
|
||||
interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf("0");
|
||||
}
|
||||
|
||||
totalPrincipal = totalPrincipal.plus(principalForInstallment);
|
||||
totalInterest = totalInterest.plus(interestForInstallment);
|
||||
|
||||
if (periodNumber == loanScheduleInfo.getNumberOfRepayments()) {
|
||||
Money principalDifference = totalPrincipal.minus(loanScheduleInfo.getPrincipal());
|
||||
if (principalDifference.isLessThanZero()) {
|
||||
principalForInstallment = principalForInstallment.plus(principalDifference.abs());
|
||||
} else if (principalDifference.isGreaterThanZero()) {
|
||||
principalForInstallment = principalForInstallment.minus(principalDifference.abs());
|
||||
}
|
||||
}
|
||||
|
||||
outstandingBalance = outstandingBalance.minus(principalForInstallment);
|
||||
|
||||
Money feeChargesForInstallment = Money.zero(monetaryCurrency);
|
||||
Money penaltyChargesForInstallment = Money.zero(monetaryCurrency);
|
||||
Money totalInstallmentDue = principalForInstallment.plus(interestForInstallment).plus(feeChargesForInstallment);
|
||||
cumulativeChargesToDate = cumulativeChargesToDate.add(feeChargesForInstallment.getAmount());
|
||||
|
||||
LoanSchedulePeriodData installment = LoanSchedulePeriodData.repaymentOnlyPeriod(periodNumber, startDate, scheduledDueDate,
|
||||
principalForInstallment.getAmount(), outstandingBalance.getAmount(), interestForInstallment.getAmount(),
|
||||
feeChargesForInstallment.getAmount(), penaltyChargesForInstallment.getAmount(), totalInstallmentDue.getAmount());
|
||||
|
||||
periods.add(installment);
|
||||
|
||||
// handle cumulative fields
|
||||
loanTermInDays += daysInPeriod;
|
||||
totalPrincipalExpected = totalPrincipalExpected.add(principalForInstallment.getAmount());
|
||||
totalInterestCharged = totalInterestCharged.add(interestForInstallment.getAmount());
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(totalInstallmentDue.getAmount());
|
||||
startDate = scheduledDueDate;
|
||||
|
||||
periodNumber++;
|
||||
}
|
||||
|
||||
final CurrencyData currencyData = new CurrencyData(currency.getCode(), currency.getName(),
|
||||
monetaryCurrency.getDigitsAfterDecimal(), currency.getDisplaySymbol(), currency.getNameCode());
|
||||
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, totalPrincipalDisbursed, totalPrincipalExpected,
|
||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalWaived, totalWrittenOff,
|
||||
totalRepaymentExpected, totalRepayment, totalOutstanding);
|
||||
}
|
||||
}
|
||||
+19
-13
@@ -75,10 +75,17 @@ public class FlatMethodLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||
periods.add(disbursementPeriod);
|
||||
|
||||
int loanTermInDays = Integer.valueOf(0);
|
||||
BigDecimal cumulativePrincipalDisbursed = principalDisbursed.getAmount();
|
||||
BigDecimal cumulativePrincipalDue = BigDecimal.ZERO;
|
||||
BigDecimal cumulativeInterestExpected = BigDecimal.ZERO;
|
||||
BigDecimal totalExpectedRepayment = chargesDueAtTimeOfDisbursement;
|
||||
BigDecimal totalPrincipalDisbursed = principalDisbursed.getAmount();
|
||||
BigDecimal totalPrincipalExpected = BigDecimal.ZERO;
|
||||
BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
|
||||
BigDecimal totalInterestCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalFeeChargesCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalPenaltyChargesCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalWaived = BigDecimal.ZERO;
|
||||
BigDecimal totalWrittenOff = BigDecimal.ZERO;
|
||||
BigDecimal totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
|
||||
BigDecimal totalRepayment = BigDecimal.ZERO;
|
||||
BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||
|
||||
LocalDate startDate = disbursementDate;
|
||||
int periodNumber = 1;
|
||||
@@ -128,21 +135,20 @@ public class FlatMethodLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||
|
||||
// handle cumulative fields
|
||||
loanTermInDays += daysInPeriod;
|
||||
cumulativePrincipalDue = cumulativePrincipalDue.add(principalPerInstallment.getAmount());
|
||||
cumulativeInterestExpected = cumulativeInterestExpected.add(interestPerInstallment.getAmount());
|
||||
totalExpectedRepayment = totalExpectedRepayment.add(totalInstallmentDue.getAmount());
|
||||
totalPrincipalExpected = totalPrincipalExpected.add(principalPerInstallment.getAmount());
|
||||
totalInterestCharged = totalInterestCharged.add(interestPerInstallment.getAmount());
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(totalInstallmentDue.getAmount());
|
||||
startDate = scheduledDueDate;
|
||||
|
||||
periodNumber++;
|
||||
}
|
||||
|
||||
final BigDecimal cumulativePrincipalOutstanding = cumulativePrincipalDisbursed.subtract(cumulativePrincipalDue);
|
||||
final CurrencyData currencyData = new CurrencyData(currency.getCode(), currency.getName(),
|
||||
monetaryCurrency.getDigitsAfterDecimal(), currency.getDisplaySymbol(), currency.getNameCode());
|
||||
|
||||
CurrencyData currencyData = new CurrencyData(currency.getCode(), currency.getName(), monetaryCurrency.getDigitsAfterDecimal(),
|
||||
currency.getDisplaySymbol(), currency.getNameCode());
|
||||
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, totalPrincipalDisbursed, totalPrincipalExpected,
|
||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalWaived, totalWrittenOff,
|
||||
totalRepaymentExpected, totalRepayment, totalOutstanding);
|
||||
}
|
||||
|
||||
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
|
||||
|
||||
+9
-2
@@ -33,8 +33,10 @@ import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCollateral;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
@@ -76,6 +78,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private final LoanCollateralAssembler loanCollateralAssembler;
|
||||
private final AprCalculator aprCalculator;
|
||||
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
|
||||
private final LoanSummaryWrapper loanSummaryWrapper;
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||
|
||||
@Autowired
|
||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||
@@ -85,7 +89,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final LoanCollateralAssembler loanCollateralAssembler, final LoanRepository loanRepository,
|
||||
final NoteRepository noteRepository, final LoanScheduleCalculationPlatformService calculationPlatformService,
|
||||
final ClientRepository clientRepository, final LoanProductRepository loanProductRepository,
|
||||
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory) {
|
||||
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final LoanSummaryWrapper loanSummaryWrapper,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
|
||||
this.context = context;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
||||
@@ -100,6 +105,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.clientRepository = clientRepository;
|
||||
this.loanProductRepository = loanProductRepository;
|
||||
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
|
||||
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
@@ -231,7 +238,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
final LoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query);
|
||||
existingLoanApplication.updateLoanSchedule(loanSchedule);
|
||||
existingLoanApplication.updateLoanScheduleDependentDerivedFields();
|
||||
}
|
||||
|
||||
this.loanRepository.saveAndFlush(existingLoanApplication);
|
||||
@@ -439,6 +445,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private Loan retrieveLoanBy(final Long loanId) {
|
||||
final Loan loan = this.loanRepository.findOne(loanId);
|
||||
if (loan == null) { throw new LoanNotFoundException(loanId); }
|
||||
loan.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory);
|
||||
return loan;
|
||||
}
|
||||
}
|
||||
+14
-3
@@ -34,7 +34,9 @@ import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCollateral;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanSchedule;
|
||||
@@ -63,13 +65,17 @@ public class LoanAssembler {
|
||||
private final LoanChargeAssembler loanChargeAssembler;
|
||||
private final LoanCollateralAssembler loanCollateralAssembler;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final LoanSummaryWrapper loanSummaryWrapper;
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||
|
||||
@Autowired
|
||||
public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository,
|
||||
final ClientRepository clientRepository, final GroupRepository groupRepository, final FundRepository fundRepository,
|
||||
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository,
|
||||
final StaffRepository staffRepository, final CodeValueRepositoryWrapper codeValueRepository,
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final LoanChargeAssembler loanChargeAssembler, final LoanCollateralAssembler loanCollateralAssembler) {
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final LoanChargeAssembler loanChargeAssembler,
|
||||
final LoanCollateralAssembler loanCollateralAssembler, final LoanSummaryWrapper loanSummaryWrapper,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.loanProductRepository = loanProductRepository;
|
||||
this.clientRepository = clientRepository;
|
||||
@@ -81,6 +87,8 @@ public class LoanAssembler {
|
||||
this.loanScheduleAssembler = loanScheduleAssembler;
|
||||
this.loanChargeAssembler = loanChargeAssembler;
|
||||
this.loanCollateralAssembler = loanCollateralAssembler;
|
||||
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
}
|
||||
|
||||
public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) {
|
||||
@@ -148,8 +156,11 @@ public class LoanAssembler {
|
||||
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element);
|
||||
|
||||
if (loanApplication == null) { throw new IllegalStateException("No loan application exists for either a client or group (or both)."); }
|
||||
loanApplication.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper,
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory);
|
||||
|
||||
loanApplication.loanApplicationSubmittal(currentUser, loanSchedule, defaultLoanLifecycleStateMachine(), submittedOnDate, externalId);
|
||||
loanApplication
|
||||
.loanApplicationSubmittal(currentUser, loanSchedule, defaultLoanLifecycleStateMachine(), submittedOnDate, externalId);
|
||||
|
||||
return loanApplication;
|
||||
}
|
||||
@@ -158,7 +169,7 @@ public class LoanAssembler {
|
||||
List<LoanStatus> allowedLoanStatuses = Arrays.asList(LoanStatus.values());
|
||||
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
|
||||
}
|
||||
|
||||
|
||||
public CodeValue findCodeValueByIdIfProvided(final Long codeValueId) {
|
||||
CodeValue codeValue = null;
|
||||
if (codeValueId != null) {
|
||||
|
||||
+216
-148
@@ -11,6 +11,7 @@ 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.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
@@ -31,6 +32,7 @@ import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanApplicationTimelineData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanSummaryData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||
@@ -47,8 +49,10 @@ import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||
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.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -90,11 +94,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
String sql = "select " + rm.loanSchema() + " where l.id = ?";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanId });
|
||||
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
throw new LoanNotFoundException(loanId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,85 +106,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
try {
|
||||
context.authenticatedUser();
|
||||
|
||||
final DisbursementData disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
||||
final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor(
|
||||
repaymentScheduleRelatedLoanData);
|
||||
final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment";
|
||||
|
||||
final LoanScheduleMapper rm = new LoanScheduleMapper(disbursement);
|
||||
final String sql = "select " + rm.loanScheduleSchema() + " where l.id = ? order by ls.loan_id, ls.installment";
|
||||
|
||||
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||
disbursement.disbursementDate(), disbursement.amount(),
|
||||
repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement(), disbursement.isDisbursed());
|
||||
|
||||
final Collection<LoanSchedulePeriodData> repaymentSchedulePeriods = this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||
|
||||
final Collection<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>(repaymentSchedulePeriods.size() + 1);
|
||||
periods.add(disbursementPeriod);
|
||||
periods.addAll(repaymentSchedulePeriods);
|
||||
|
||||
LoanSchedulePeriodDataWrapper wrapper = new LoanSchedulePeriodDataWrapper(periods);
|
||||
|
||||
final Integer loanTermInDays = wrapper.deriveCumulativeLoanTermInDays();
|
||||
|
||||
final BigDecimal cumulativePrincipalDisbursed = wrapper.deriveCumulativePrincipalDisbursed();
|
||||
final BigDecimal cumulativePrincipalDue = wrapper.deriveCumulativePrincipalDue();
|
||||
final BigDecimal cumulativePrincipalPaid = wrapper.deriveCumulativePrincipalPaid();
|
||||
final BigDecimal cumulativePrincipalWrittenOff = wrapper.deriveCumulativePrincipalWrittenOff();
|
||||
final BigDecimal cumulativePrincipalOutstanding = wrapper.deriveCumulativePrincipalOutstanding();
|
||||
|
||||
final BigDecimal cumulativeInterestExpected = wrapper.deriveCumulativeInterestExpected();
|
||||
final BigDecimal cumulativeInterestPaid = wrapper.deriveCumulativeInterestPaid();
|
||||
final BigDecimal cumulativeInterestWaived = wrapper.deriveCumulativeInterestWaived();
|
||||
final BigDecimal cumulativeInterestWrittenOff = wrapper.deriveCumulativeInterestWrittenOff();
|
||||
final BigDecimal cumulativeInterestOutstanding = wrapper.deriveCumulativeInterestOutstanding();
|
||||
|
||||
final BigDecimal cumulativeFeeChargesExpected = wrapper.deriveCumulativeFeeChargesToDate();
|
||||
final BigDecimal cumulativeFeeChargesPaid = wrapper.deriveCumulativeFeeChargesPaid();
|
||||
final BigDecimal cumulativeFeeChargesWaived = wrapper.deriveCumulativeFeeChargesWaived();
|
||||
final BigDecimal cumulativeFeeChargesWrittenOff = wrapper.deriveCumulativeFeeChargesWrittenOff();
|
||||
final BigDecimal cumulativeFeeChargesOutstanding = wrapper.deriveCumulativeFeeChargesOutstanding();
|
||||
|
||||
final BigDecimal cumulativePenaltyChargesExpected = wrapper.deriveCumulativePenaltyChargesToDate();
|
||||
final BigDecimal cumulativePenaltyChargesPaid = wrapper.deriveCumulativePenaltyChargesPaid();
|
||||
final BigDecimal cumulativePenaltyChargesWaived = wrapper.deriveCumulativePenaltyChargesWaived();
|
||||
final BigDecimal cumulativePenaltyChargesWrittenOff = wrapper.deriveCumulativePenaltyChargesWrittenOff();
|
||||
final BigDecimal cumulativePenaltyChargesOutstanding = wrapper.deriveCumulativePenaltyChargesOutstanding();
|
||||
|
||||
final BigDecimal totalExpectedCostOfLoan = cumulativeInterestExpected.add(cumulativeFeeChargesExpected).add(
|
||||
cumulativePenaltyChargesExpected);
|
||||
final BigDecimal totalExpectedRepayment = cumulativePrincipalDisbursed.add(totalExpectedCostOfLoan);
|
||||
|
||||
final BigDecimal totalPaidToDate = cumulativePrincipalPaid.add(cumulativeInterestPaid).add(cumulativeFeeChargesPaid)
|
||||
.add(cumulativePenaltyChargesPaid);
|
||||
final BigDecimal totalWaivedToDate = cumulativeInterestWaived.add(cumulativeFeeChargesWaived).add(
|
||||
cumulativePenaltyChargesWaived);
|
||||
final BigDecimal totalWrittenOffToDate = cumulativePrincipalWrittenOff.add(cumulativeInterestWrittenOff)
|
||||
.add(cumulativeFeeChargesWrittenOff).add(cumulativePenaltyChargesWrittenOff);
|
||||
|
||||
final BigDecimal totalOutstanding = cumulativePrincipalOutstanding.add(cumulativeInterestOutstanding)
|
||||
.add(cumulativeFeeChargesOutstanding).add(cumulativePenaltyChargesOutstanding);
|
||||
|
||||
final BigDecimal totalOverdue = wrapper.deriveCumulativeTotalOverdue();
|
||||
|
||||
final CurrencyData currency = repaymentScheduleRelatedLoanData.getCurrency();
|
||||
final MonetaryCurrency monetaryCurrency = new MonetaryCurrency(currency.code(), currency.decimalPlaces());
|
||||
final Money tolerance = Money.of(monetaryCurrency, repaymentScheduleRelatedLoanData.getInArrearsTolerance());
|
||||
final Money totalOverdueMoney = Money.of(monetaryCurrency, totalOverdue);
|
||||
boolean isWaiveAllowed = totalOverdueMoney.isGreaterThanZero()
|
||||
&& (tolerance.isGreaterThan(totalOverdueMoney) || tolerance.isEqualTo(totalOverdueMoney));
|
||||
|
||||
BigDecimal totalInArrears = null;
|
||||
if (!isWaiveAllowed) {
|
||||
totalInArrears = totalOverdueMoney.getAmount();
|
||||
}
|
||||
|
||||
return new LoanScheduleData(currency, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
cumulativePrincipalPaid, cumulativePrincipalWrittenOff, cumulativePrincipalOutstanding, cumulativeInterestExpected,
|
||||
cumulativeInterestPaid, cumulativeInterestWaived, cumulativeInterestWrittenOff, cumulativeInterestOutstanding,
|
||||
cumulativeFeeChargesExpected, cumulativeFeeChargesPaid, cumulativeFeeChargesWaived, cumulativeFeeChargesWrittenOff,
|
||||
cumulativeFeeChargesOutstanding, cumulativePenaltyChargesExpected, cumulativePenaltyChargesPaid,
|
||||
cumulativePenaltyChargesWaived, cumulativePenaltyChargesWrittenOff, cumulativePenaltyChargesOutstanding,
|
||||
totalExpectedCostOfLoan, totalExpectedRepayment, totalPaidToDate, totalWaivedToDate, totalWrittenOffToDate,
|
||||
totalOutstanding, totalInArrears);
|
||||
return this.jdbcTemplate.query(sql, fullResultsetExtractor, new Object[] { loanId });
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
throw new LoanNotFoundException(loanId);
|
||||
}
|
||||
@@ -342,9 +270,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.approvedon_date as approvedOnDate, abu.username as approvedByUsername, abu.firstname as approvedByFirstname, abu.lastname as approvedByLastname,"
|
||||
+ " l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate, dbu.username as disbursedByUsername, dbu.firstname as disbursedByFirstname, dbu.lastname as disbursedByLastname,"
|
||||
+ " l.closedon_date as closedOnDate, cbu.username as closedByUsername, cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname,"
|
||||
|
||||
+ " l.expected_firstrepaymenton_date as expectedFirstRepaymentOnDate, l.interest_calculated_from_date as interestChargedFromDate, l.expected_maturedon_date as expectedMaturityDate, "
|
||||
+ " l.total_charges_due_at_disbursement_derived as totalDisbursementCharges,"
|
||||
+ " l.principal_amount as principal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery,"
|
||||
+ " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
|
||||
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
|
||||
@@ -352,10 +278,47 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
|
||||
+ " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, "
|
||||
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
|
||||
+ " l.loan_officer_id as loanOfficerId, s.display_name as loanOfficerName" + " from m_loan l"
|
||||
+ " left join m_client c on c.id = l.client_id" + " left join m_group g on g.id = l.group_id"
|
||||
+ " join m_product_loan lp on lp.id = l.product_id" + " join m_currency rc on rc.`code` = l.currency_code"
|
||||
+ " left join m_fund f on f.id = l.fund_id" + " left join m_staff s on s.id = l.loan_officer_id"
|
||||
+ " l.loan_officer_id as loanOfficerId, s.display_name as loanOfficerName, "
|
||||
+ " l.principal_disbursed_derived as principalDisbursed,"
|
||||
+ " l.principal_repaid_derived as principalPaid,"
|
||||
+ " l.principal_writtenoff_derived as principalWrittenOff,"
|
||||
+ " l.principal_outstanding_derived as principalOutstanding,"
|
||||
+ " l.principal_overdue_derived as principalOverdue,"
|
||||
+ " l.interest_charged_derived as interestCharged,"
|
||||
+ " l.interest_repaid_derived as interestPaid,"
|
||||
+ " l.interest_waived_derived as interestWaived,"
|
||||
+ " l.interest_writtenoff_derived as interestWrittenOff,"
|
||||
+ " l.interest_outstanding_derived as interestOutstanding,"
|
||||
+ " l.interest_overdue_derived as interestOverdue,"
|
||||
+ " l.fee_charges_charged_derived as feeChargesCharged,"
|
||||
+ " l.total_charges_due_at_disbursement_derived as feeChargesDueAtDisbursementCharged,"
|
||||
+ " l.fee_charges_repaid_derived as feeChargesPaid,"
|
||||
+ " l.fee_charges_waived_derived as feeChargesWaived,"
|
||||
+ " l.fee_charges_writtenoff_derived as feeChargesWrittenOff,"
|
||||
+ " l.fee_charges_outstanding_derived as feeChargesOutstanding,"
|
||||
+ " l.fee_charges_overdue_derived as feeChargesOverdue,"
|
||||
+ " l.penalty_charges_charged_derived as penaltyChargesCharged,"
|
||||
+ " l.penalty_charges_repaid_derived as penaltyChargesPaid,"
|
||||
+ " l.penalty_charges_waived_derived as penaltyChargesWaived,"
|
||||
+ " l.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff,"
|
||||
+ " l.penalty_charges_outstanding_derived as penaltyChargesOutstanding,"
|
||||
+ " l.penalty_charges_overdue_derived as penaltyChargesOverdue,"
|
||||
+ " l.total_expected_repayment_derived as totalExpectedRepayment,"
|
||||
+ " l.total_repayment_derived as totalRepayment,"
|
||||
+ " l.total_expected_costofloan_derived as totalExpectedCostOfLoan,"
|
||||
+ " l.total_costofloan_derived as totalCostOfLoan,"
|
||||
+ " l.total_waived_derived as totalWaived,"
|
||||
+ " l.total_writtenoff_derived as totalWrittenOff,"
|
||||
+ " l.total_outstanding_derived as totalOutstanding,"
|
||||
+ " l.total_overdue_derived as totalOverdue,"
|
||||
+ " l.overdue_since_date_derived as overdueSinceDate"
|
||||
+ " from m_loan l" //
|
||||
+ " left join m_client c on c.id = l.client_id" //
|
||||
+ " left join m_group g on g.id = l.group_id" //
|
||||
+ " join m_product_loan lp on lp.id = l.product_id" //
|
||||
+ " join m_currency rc on rc.`code` = l.currency_code" //
|
||||
+ " left join m_fund f on f.id = l.fund_id" //
|
||||
+ " left join m_staff s on s.id = l.loan_officer_id" //
|
||||
+ " left join m_appuser sbu on sbu.id = l.submittedon_userid"
|
||||
+ " left join m_appuser rbu on rbu.id = l.rejectedon_userid"
|
||||
+ " left join m_appuser wbu on wbu.id = l.withdrawnon_userid"
|
||||
@@ -443,7 +406,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
final BigDecimal principal = rs.getBigDecimal("principal");
|
||||
final BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance");
|
||||
final BigDecimal totalFeeChargesAtDisbursement = rs.getBigDecimal("totalDisbursementCharges");
|
||||
|
||||
final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
|
||||
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
|
||||
@@ -478,106 +440,212 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
|
||||
final LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
|
||||
|
||||
final BigDecimal feeChargesDueAtDisbursementCharged = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs,
|
||||
"feeChargesDueAtDisbursementCharged");
|
||||
LoanSummaryData loanSummary = null;
|
||||
if (status.id().intValue() >= 300) {
|
||||
|
||||
// loan summary
|
||||
final BigDecimal principalDisbursed = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDisbursed");
|
||||
final BigDecimal principalPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalPaid");
|
||||
final BigDecimal principalWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalWrittenOff");
|
||||
final BigDecimal principalOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalOutstanding");
|
||||
final BigDecimal principalOverdue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalOverdue");
|
||||
|
||||
final BigDecimal interestCharged = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestCharged");
|
||||
final BigDecimal interestPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestPaid");
|
||||
final BigDecimal interestWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWaived");
|
||||
final BigDecimal interestWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWrittenOff");
|
||||
final BigDecimal interestOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestOutstanding");
|
||||
final BigDecimal interestOverdue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestOverdue");
|
||||
|
||||
final BigDecimal feeChargesCharged = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesCharged");
|
||||
final BigDecimal feeChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesPaid");
|
||||
final BigDecimal feeChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWaived");
|
||||
final BigDecimal feeChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWrittenOff");
|
||||
final BigDecimal feeChargesOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesOutstanding");
|
||||
final BigDecimal feeChargesOverdue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesOverdue");
|
||||
|
||||
final BigDecimal penaltyChargesCharged = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesCharged");
|
||||
final BigDecimal penaltyChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesPaid");
|
||||
final BigDecimal penaltyChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWaived");
|
||||
final BigDecimal penaltyChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWrittenOff");
|
||||
final BigDecimal penaltyChargesOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesOutstanding");
|
||||
final BigDecimal penaltyChargesOverdue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesOverdue");
|
||||
|
||||
final BigDecimal totalExpectedRepayment = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalExpectedRepayment");
|
||||
final BigDecimal totalRepayment = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalRepayment");
|
||||
final BigDecimal totalExpectedCostOfLoan = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalExpectedCostOfLoan");
|
||||
final BigDecimal totalCostOfLoan = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalCostOfLoan");
|
||||
final BigDecimal totalWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalWaived");
|
||||
final BigDecimal totalWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalWrittenOff");
|
||||
final BigDecimal totalOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalOutstanding");
|
||||
final BigDecimal totalOverdue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalOverdue");
|
||||
|
||||
final LocalDate overdueSinceDate = JdbcSupport.getLocalDate(rs, "overdueSinceDate");
|
||||
|
||||
loanSummary = new LoanSummaryData(currencyData, principalDisbursed, principalPaid, principalWrittenOff,
|
||||
principalOutstanding, principalOverdue, interestCharged, interestPaid, interestWaived, interestWrittenOff,
|
||||
interestOutstanding, interestOverdue, feeChargesCharged, feeChargesDueAtDisbursementCharged, feeChargesPaid,
|
||||
feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, feeChargesOverdue, penaltyChargesCharged,
|
||||
penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding,
|
||||
penaltyChargesOverdue, totalExpectedRepayment, totalRepayment, totalExpectedCostOfLoan, totalCostOfLoan,
|
||||
totalWaived, totalWrittenOff, totalOutstanding, totalOverdue, overdueSinceDate);
|
||||
}
|
||||
|
||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupId,
|
||||
groupName, groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId,
|
||||
loanPurposeName, loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency,
|
||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionStrategyId,
|
||||
amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
|
||||
interestCalculationPeriodType, expectedFirstRepaymentOnDate, interestChargedFromDate, timeline,
|
||||
totalFeeChargesAtDisbursement);
|
||||
interestCalculationPeriodType, expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, loanSummary,
|
||||
feeChargesDueAtDisbursementCharged);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LoanScheduleMapper implements RowMapper<LoanSchedulePeriodData> {
|
||||
private static final class LoanScheduleResultSetExtractor implements ResultSetExtractor<LoanScheduleData> {
|
||||
|
||||
private final CurrencyData currency;
|
||||
private final DisbursementData disbursement;
|
||||
private final BigDecimal totalFeeChargesDueAtDisbursement;
|
||||
private LocalDate lastDueDate;
|
||||
private BigDecimal outstandingLoanPrincipalBalance;
|
||||
|
||||
public LoanScheduleMapper(final DisbursementData disbursement) {
|
||||
public LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData) {
|
||||
this.currency = repaymentScheduleRelatedLoanData.getCurrency();
|
||||
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
||||
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
||||
this.lastDueDate = disbursement.disbursementDate();
|
||||
this.outstandingLoanPrincipalBalance = disbursement.amount();
|
||||
}
|
||||
|
||||
public String loanScheduleSchema() {
|
||||
public String schema() {
|
||||
|
||||
return " ls.loan_id as loanId, ls.installment as period, ls.fromdate as fromDate, ls.duedate as dueDate, "
|
||||
+ " ls.principal_amount as principalDue, ls.principal_completed_derived as principalPaid, ls.principal_writtenoff_derived as principalWrittenOff, "
|
||||
+ " ls.interest_amount as interestDue, ls.interest_completed_derived as interestPaid, ls.interest_waived_derived as interestWaived, ls.interest_writtenoff_derived as interestWrittenOff, "
|
||||
+ " ls.fee_charges_amount as feeChargesDue, ls.fee_charges_completed_derived as feeChargesPaid, ls.fee_charges_waived_derived as feeChargesWaived, ls.fee_charges_writtenoff_derived as feeChargesWrittenOff, "
|
||||
+ " ls.penalty_charges_amount as penaltyChargesDue, ls.penalty_charges_completed_derived as penaltyChargesPaid, ls.penalty_charges_waived_derived as penaltyChargesWaived, ls.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff "
|
||||
+ " from m_loan l " + " join m_loan_repayment_schedule ls on ls.loan_id = l.id ";
|
||||
+ " from m_loan_repayment_schedule ls ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanSchedulePeriodData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
public LoanScheduleData extractData(final ResultSet rs) throws SQLException, DataAccessException {
|
||||
|
||||
final Long loanId = rs.getLong("loanId");
|
||||
final Integer period = JdbcSupport.getInteger(rs, "period");
|
||||
LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromDate");
|
||||
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
|
||||
final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDue");
|
||||
final BigDecimal principalPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalPaid");
|
||||
final BigDecimal principalWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalWrittenOff");
|
||||
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||
this.disbursement.disbursementDate(), this.disbursement.amount(), this.totalFeeChargesDueAtDisbursement,
|
||||
this.disbursement.isDisbursed());
|
||||
|
||||
// TODO - KW - rather than calculate this here should we put
|
||||
// calculation on derived column on table like other columns?
|
||||
final BigDecimal principalOutstanding = principalDue.subtract(principalPaid).subtract(principalWrittenOff);
|
||||
final Collection<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>();
|
||||
periods.add(disbursementPeriod);
|
||||
|
||||
final BigDecimal interestExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestDue");
|
||||
final BigDecimal interestPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestPaid");
|
||||
final BigDecimal interestWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWaived");
|
||||
final BigDecimal interestWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWrittenOff");
|
||||
final MonetaryCurrency monCurrency = new MonetaryCurrency(this.currency.code(), this.currency.decimalPlaces());
|
||||
final BigDecimal totalPrincipalDisbursed = Money.of(monCurrency, this.disbursement.amount()).getAmount();
|
||||
Money totalPrincipalExpected = Money.zero(monCurrency);
|
||||
Money totalPrincipalPaid = Money.zero(monCurrency);
|
||||
Money totalInterestCharged = Money.zero(monCurrency);
|
||||
Money totalFeeChargesCharged = Money.zero(monCurrency);
|
||||
Money totalPenaltyChargesCharged = Money.zero(monCurrency);
|
||||
Money totalWaived = Money.zero(monCurrency);
|
||||
Money totalWrittenOff = Money.zero(monCurrency);
|
||||
Money totalRepaymentExpected = Money.zero(monCurrency);
|
||||
Money totalRepayment = Money.zero(monCurrency);
|
||||
Money totalOutstanding = Money.zero(monCurrency);
|
||||
|
||||
// TODO - KW - rather than calculate this here should we put
|
||||
// calculation on derived column on table like other columns?
|
||||
final BigDecimal interestActualDue = interestExpectedDue.subtract(interestWaived).subtract(interestWrittenOff);
|
||||
final BigDecimal interestOutstanding = interestActualDue.subtract(interestPaid);
|
||||
Integer loanTermInDays = Integer.valueOf(0);
|
||||
while (rs.next()) {
|
||||
|
||||
final BigDecimal feeChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesDue");
|
||||
final BigDecimal feeChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesPaid");
|
||||
final BigDecimal feeChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWaived");
|
||||
final BigDecimal feeChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWrittenOff");
|
||||
final Long loanId = rs.getLong("loanId");
|
||||
final Integer period = JdbcSupport.getInteger(rs, "period");
|
||||
LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromDate");
|
||||
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
|
||||
|
||||
final BigDecimal feeChargesActualDue = feeChargesExpectedDue.subtract(feeChargesWaived).subtract(feeChargesWrittenOff);
|
||||
final BigDecimal feeChargesOutstanding = feeChargesActualDue.subtract(feeChargesPaid);
|
||||
Integer daysInPeriod = Integer.valueOf(0);
|
||||
if (fromDate != null) {
|
||||
daysInPeriod = Days.daysBetween(fromDate, dueDate).getDays();
|
||||
loanTermInDays = Integer.valueOf(loanTermInDays.intValue() + daysInPeriod.intValue());
|
||||
}
|
||||
|
||||
final BigDecimal penaltyChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesDue");
|
||||
final BigDecimal penaltyChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesPaid");
|
||||
final BigDecimal penaltyChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWaived");
|
||||
final BigDecimal penaltyChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWrittenOff");
|
||||
final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDue");
|
||||
totalPrincipalExpected = totalPrincipalExpected.plus(principalDue);
|
||||
final BigDecimal principalPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalPaid");
|
||||
totalPrincipalPaid = totalPrincipalPaid.plus(principalPaid);
|
||||
final BigDecimal principalWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalWrittenOff");
|
||||
|
||||
final BigDecimal penaltyChargesActualDue = penaltyChargesExpectedDue.subtract(penaltyChargesWaived).subtract(
|
||||
penaltyChargesWrittenOff);
|
||||
final BigDecimal penaltyChargesOutstanding = penaltyChargesActualDue.subtract(penaltyChargesPaid);
|
||||
final BigDecimal principalOutstanding = principalDue.subtract(principalPaid).subtract(principalWrittenOff);
|
||||
|
||||
final BigDecimal totalExpectedCostOfLoanForPeriod = interestExpectedDue.add(feeChargesExpectedDue).add(
|
||||
penaltyChargesExpectedDue);
|
||||
final BigDecimal interestExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestDue");
|
||||
totalInterestCharged = totalInterestCharged.plus(interestExpectedDue);
|
||||
final BigDecimal interestPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestPaid");
|
||||
final BigDecimal interestWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWaived");
|
||||
final BigDecimal interestWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWrittenOff");
|
||||
|
||||
final BigDecimal totalDueForPeriod = principalDue.add(totalExpectedCostOfLoanForPeriod);
|
||||
final BigDecimal totalPaidForPeriod = principalPaid.add(interestPaid).add(feeChargesPaid).add(penaltyChargesPaid);
|
||||
final BigDecimal totalWaivedForPeriod = interestWaived.add(feeChargesWaived).add(penaltyChargesWaived);
|
||||
final BigDecimal totalWrittenOffForPeriod = principalWrittenOff.add(interestWrittenOff).add(feeChargesWrittenOff)
|
||||
.add(penaltyChargesWrittenOff);
|
||||
final BigDecimal totalOutstandingForPeriod = principalOutstanding.add(interestOutstanding).add(feeChargesOutstanding)
|
||||
.add(penaltyChargesOutstanding);
|
||||
final BigDecimal interestActualDue = interestExpectedDue.subtract(interestWaived).subtract(interestWrittenOff);
|
||||
final BigDecimal interestOutstanding = interestActualDue.subtract(interestPaid);
|
||||
|
||||
final BigDecimal totalActualCostOfLoanForPeriod = interestActualDue.add(feeChargesActualDue).add(penaltyChargesActualDue);
|
||||
final BigDecimal feeChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesDue");
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.plus(feeChargesExpectedDue);
|
||||
final BigDecimal feeChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesPaid");
|
||||
final BigDecimal feeChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWaived");
|
||||
final BigDecimal feeChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWrittenOff");
|
||||
|
||||
if (fromDate == null) {
|
||||
fromDate = this.lastDueDate;
|
||||
final BigDecimal feeChargesActualDue = feeChargesExpectedDue.subtract(feeChargesWaived).subtract(feeChargesWrittenOff);
|
||||
final BigDecimal feeChargesOutstanding = feeChargesActualDue.subtract(feeChargesPaid);
|
||||
|
||||
final BigDecimal penaltyChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesDue");
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.plus(penaltyChargesExpectedDue);
|
||||
final BigDecimal penaltyChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesPaid");
|
||||
final BigDecimal penaltyChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWaived");
|
||||
final BigDecimal penaltyChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWrittenOff");
|
||||
|
||||
final BigDecimal penaltyChargesActualDue = penaltyChargesExpectedDue.subtract(penaltyChargesWaived).subtract(
|
||||
penaltyChargesWrittenOff);
|
||||
final BigDecimal penaltyChargesOutstanding = penaltyChargesActualDue.subtract(penaltyChargesPaid);
|
||||
|
||||
final BigDecimal totalExpectedCostOfLoanForPeriod = interestExpectedDue.add(feeChargesExpectedDue).add(
|
||||
penaltyChargesExpectedDue);
|
||||
|
||||
final BigDecimal totalDueForPeriod = principalDue.add(totalExpectedCostOfLoanForPeriod);
|
||||
final BigDecimal totalPaidForPeriod = principalPaid.add(interestPaid).add(feeChargesPaid).add(penaltyChargesPaid);
|
||||
final BigDecimal totalWaivedForPeriod = interestWaived.add(feeChargesWaived).add(penaltyChargesWaived);
|
||||
totalWaived = totalWaived.plus(totalWaivedForPeriod);
|
||||
final BigDecimal totalWrittenOffForPeriod = principalWrittenOff.add(interestWrittenOff).add(feeChargesWrittenOff)
|
||||
.add(penaltyChargesWrittenOff);
|
||||
totalWrittenOff = totalWrittenOff.plus(totalWrittenOffForPeriod);
|
||||
final BigDecimal totalOutstandingForPeriod = principalOutstanding.add(interestOutstanding).add(feeChargesOutstanding)
|
||||
.add(penaltyChargesOutstanding);
|
||||
|
||||
final BigDecimal totalActualCostOfLoanForPeriod = interestActualDue.add(feeChargesActualDue).add(penaltyChargesActualDue);
|
||||
|
||||
totalRepaymentExpected = totalRepaymentExpected.plus(totalDueForPeriod);
|
||||
totalRepayment = totalRepayment.plus(totalPaidForPeriod);
|
||||
totalOutstanding = totalOutstanding.plus(totalOutstandingForPeriod);
|
||||
|
||||
if (fromDate == null) {
|
||||
fromDate = this.lastDueDate;
|
||||
}
|
||||
final BigDecimal outstandingPrincipleBalanceOfLoan = outstandingLoanPrincipalBalance.subtract(principalDue);
|
||||
|
||||
// update based on current period values
|
||||
this.lastDueDate = dueDate;
|
||||
outstandingLoanPrincipalBalance = outstandingLoanPrincipalBalance.subtract(principalDue);
|
||||
|
||||
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate,
|
||||
dueDate, principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipleBalanceOfLoan,
|
||||
interestExpectedDue, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue,
|
||||
feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue,
|
||||
penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod,
|
||||
totalPaidForPeriod, totalWaivedForPeriod, totalWrittenOffForPeriod, totalOutstandingForPeriod,
|
||||
totalActualCostOfLoanForPeriod);
|
||||
|
||||
periods.add(periodData);
|
||||
}
|
||||
final BigDecimal outstandingPrincipleBalanceOfLoan = outstandingLoanPrincipalBalance.subtract(principalDue);
|
||||
|
||||
// update based on current period values
|
||||
this.lastDueDate = dueDate;
|
||||
outstandingLoanPrincipalBalance = outstandingLoanPrincipalBalance.subtract(principalDue);
|
||||
|
||||
return LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate, dueDate, principalDue, principalPaid,
|
||||
principalWrittenOff, principalOutstanding, outstandingPrincipleBalanceOfLoan, interestExpectedDue, interestPaid,
|
||||
interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue, feeChargesPaid, feeChargesWaived,
|
||||
feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue, penaltyChargesPaid, penaltyChargesWaived,
|
||||
penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, totalPaidForPeriod, totalWaivedForPeriod,
|
||||
totalWrittenOffForPeriod, totalOutstandingForPeriod, totalActualCostOfLoanForPeriod);
|
||||
return new LoanScheduleData(this.currency, periods, loanTermInDays, totalPrincipalDisbursed,
|
||||
totalPrincipalExpected.getAmount(), totalPrincipalPaid.getAmount(), totalInterestCharged.getAmount(),
|
||||
totalFeeChargesCharged.getAmount(), totalPenaltyChargesCharged.getAmount(), totalWaived.getAmount(),
|
||||
totalWrittenOff.getAmount(), totalRepaymentExpected.getAmount(), totalRepayment.getAmount(),
|
||||
totalOutstanding.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-198
@@ -1,198 +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.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
|
||||
public class LoanSchedulePeriodDataWrapper {
|
||||
|
||||
private final Collection<LoanSchedulePeriodData> periods;
|
||||
|
||||
public LoanSchedulePeriodDataWrapper(final Collection<LoanSchedulePeriodData> periods) {
|
||||
this.periods = periods;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePrincipalDisbursed() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.principalDisbursed());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePrincipalDue() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.principalDue());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePrincipalPaid() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.principalPaid());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePrincipalWrittenOff() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.principalWrittenOff());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePrincipalOutstanding() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.principalOutstanding());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeInterestExpected() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.interestDue());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeInterestPaid() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.interestPaid());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeInterestWaived() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.interestWaived());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeInterestWrittenOff() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.interestWrittenOff());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeInterestOutstanding() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.interestOutstanding());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeFeeChargesToDate() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.feeChargesDue());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeFeeChargesPaid() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.feeChargesPaid());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeFeeChargesWaived() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.feeChargesWaived());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeFeeChargesWrittenOff() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.feeChargesWrittenOff());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeFeeChargesOutstanding() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.feeChargesOutstanding());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePenaltyChargesToDate() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.penaltyChargesDue());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePenaltyChargesPaid() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.penaltyChargesPaid());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePenaltyChargesWaived() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.penaltyChargesWaived());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePenaltyChargesWrittenOff() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.penaltyChargesWrittenOff());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativePenaltyChargesOutstanding() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.penaltyChargesOutstanding());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public Integer deriveCumulativeLoanTermInDays() {
|
||||
Integer cumulativeValue = Integer.valueOf(0);
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
if (period.daysInPeriod() != null) {
|
||||
cumulativeValue += period.daysInPeriod();
|
||||
}
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
|
||||
public BigDecimal deriveCumulativeTotalOverdue() {
|
||||
BigDecimal cumulativeValue = BigDecimal.ZERO;
|
||||
for (LoanSchedulePeriodData period : this.periods) {
|
||||
cumulativeValue = cumulativeValue.add(period.totalOverdue());
|
||||
}
|
||||
return cumulativeValue;
|
||||
}
|
||||
}
|
||||
+13
-7
@@ -33,8 +33,10 @@ import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
@@ -63,6 +65,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
private final LoanChargeRepository loanChargeRepository;
|
||||
private final ApplicationCurrencyRepository applicationCurrencyRepository;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
private final LoanSummaryWrapper loanSummaryWrapper;
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||
|
||||
@Autowired
|
||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -70,9 +74,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer, final LoanAssembler loanAssembler,
|
||||
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
|
||||
final NoteRepository noteRepository, final ChargeRepositoryWrapper chargeRepository,
|
||||
final LoanChargeRepository loanChargeRepository,
|
||||
final ApplicationCurrencyRepository applicationCurrencyRepository,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepository applicationCurrencyRepository,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
|
||||
this.context = context;
|
||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||
this.loanAssembler = loanAssembler;
|
||||
@@ -84,6 +88,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
this.loanUpdateCommandFromApiJsonDeserializer = loanUpdateCommandFromApiJsonDeserializer;
|
||||
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
@@ -105,8 +111,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Map<String, Object> changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency,
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
final Map<String, Object> changes = loan.disburse(currentUser, command, currency, existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
@@ -142,8 +148,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Map<String, Object> changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
final Map<String, Object> changes = loan.undoDisbursal(existingTransactionIds, existingReversedTransactionIds);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
@@ -576,6 +581,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
private Loan retrieveLoanBy(final Long loanId) {
|
||||
final Loan loan = this.loanRepository.findOne(loanId);
|
||||
if (loan == null) { throw new LoanNotFoundException(loanId); }
|
||||
loan.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory);
|
||||
return loan;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user