mifosx-61: support waive of interest along with loan write off capability. refactor loanRepayments as transactions on api.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
alter table m_loan_repayment_schedule add column principal_writtenoff_derived decimal(19,6) DEFAULT NULL after principal_completed_derived;
|
||||
alter table m_loan_repayment_schedule add column interest_writtenoff_derived decimal(19,6) DEFAULT NULL after interest_completed_derived;
|
||||
|
||||
+44
-6
@@ -14,42 +14,57 @@ import org.mifosng.platform.api.data.LoanSchedulePeriodData;
|
||||
* <li>repayment schedule - the principal due, outstanding balance and cost of loan items such as interest and charges</li>
|
||||
* </ul>
|
||||
*/
|
||||
// TODO - KW - rename file
|
||||
@SuppressWarnings("unused")
|
||||
public class LoanScheduleNewData {
|
||||
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 charges applied on the loan to date.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeChargesToDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeChargesPaid;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal cumulativeChargesOutstanding;
|
||||
|
||||
/**
|
||||
@@ -60,23 +75,33 @@ public class LoanScheduleNewData {
|
||||
* <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.
|
||||
*/
|
||||
@@ -87,6 +112,7 @@ public class LoanScheduleNewData {
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
@@ -96,15 +122,17 @@ public class LoanScheduleNewData {
|
||||
*/
|
||||
private final Collection<LoanSchedulePeriodData> periods;
|
||||
|
||||
public LoanScheduleNewData() {
|
||||
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.cumulativeChargesToDate = null;
|
||||
@@ -116,6 +144,7 @@ public class LoanScheduleNewData {
|
||||
this.totalExpectedRepayment = null;
|
||||
this.totalPaidToDate = null;
|
||||
this.totalWaivedToDate = null;
|
||||
this.totalWrittenOffToDate = null;
|
||||
this.totalOutstanding = null;
|
||||
this.totalInArrears = null;
|
||||
|
||||
@@ -124,7 +153,7 @@ public class LoanScheduleNewData {
|
||||
this.loanTermInDays = null;
|
||||
}
|
||||
|
||||
public LoanScheduleNewData(
|
||||
public LoanScheduleData(
|
||||
final CurrencyData currency,
|
||||
final Collection<LoanSchedulePeriodData> periods,
|
||||
final Integer loanTermInDays,
|
||||
@@ -141,11 +170,13 @@ public class LoanScheduleNewData {
|
||||
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.cumulativeChargesToDate = cumulativeChargesToDate;
|
||||
@@ -163,6 +194,7 @@ public class LoanScheduleNewData {
|
||||
this.totalExpectedRepayment = totalExpectedRepayment;
|
||||
this.totalPaidToDate = BigDecimal.ZERO;
|
||||
this.totalWaivedToDate = BigDecimal.ZERO;
|
||||
this.totalWrittenOffToDate = BigDecimal.ZERO;
|
||||
this.totalOutstanding = totalExpectedRepayment;
|
||||
this.totalInArrears = BigDecimal.ZERO;
|
||||
}
|
||||
@@ -170,15 +202,17 @@ public class LoanScheduleNewData {
|
||||
/*
|
||||
* Used when fully populating
|
||||
*/
|
||||
public LoanScheduleNewData(final CurrencyData currency, final Collection<LoanSchedulePeriodData> periods,
|
||||
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 cumulativeChargesToDate,
|
||||
final BigDecimal cumulativeChargesPaid,
|
||||
@@ -187,6 +221,7 @@ public class LoanScheduleNewData {
|
||||
final BigDecimal totalExpectedRepayment,
|
||||
final BigDecimal totalPaidToDate,
|
||||
final BigDecimal totalWaivedToDate,
|
||||
final BigDecimal totalWrittenOffToDate,
|
||||
final BigDecimal totalOutstanding,
|
||||
final BigDecimal totalInArrears) {
|
||||
this.currency = currency;
|
||||
@@ -196,9 +231,11 @@ public class LoanScheduleNewData {
|
||||
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.cumulativeChargesToDate = cumulativeChargesToDate;
|
||||
@@ -208,6 +245,7 @@ public class LoanScheduleNewData {
|
||||
this.totalExpectedRepayment = totalExpectedRepayment;
|
||||
this.totalPaidToDate = totalPaidToDate;
|
||||
this.totalWaivedToDate = totalWaivedToDate;
|
||||
this.totalWrittenOffToDate = totalWrittenOffToDate;
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
this.totalInArrears = totalInArrears;
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import org.mifosng.platform.api.data.LoanBasicDetailsData;
|
||||
import org.mifosng.platform.api.data.LoanChargeData;
|
||||
import org.mifosng.platform.api.data.LoanPermissionData;
|
||||
import org.mifosng.platform.api.data.LoanProductLookup;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionNewData;
|
||||
import org.mifosng.platform.api.data.MoneyData;
|
||||
@@ -191,8 +190,8 @@ public class LoansApiResource {
|
||||
LoanBasicDetailsData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId);
|
||||
|
||||
int loanRepaymentsCount = 0;
|
||||
Collection<LoanRepaymentTransactionData> loanRepayments = null;
|
||||
LoanScheduleNewData repaymentSchedule = null;
|
||||
Collection<LoanTransactionNewData> loanRepayments = null;
|
||||
LoanScheduleData repaymentSchedule = null;
|
||||
LoanPermissionData permissions = null;
|
||||
Collection<LoanChargeData> charges = null;
|
||||
|
||||
@@ -201,18 +200,21 @@ public class LoansApiResource {
|
||||
if (!associationParameters.isEmpty()) {
|
||||
|
||||
if (associationParameters.contains("all")) {
|
||||
responseParameters.addAll(Arrays.asList("repaymentSchedule", "loanRepayments", "permissions", "convenienceData", "charges"));
|
||||
responseParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "convenienceData", "charges"));
|
||||
} else {
|
||||
responseParameters.addAll(associationParameters);
|
||||
}
|
||||
|
||||
Collection<LoanRepaymentTransactionData> currentLoanRepayments = this.loanReadPlatformService.retrieveLoanPayments(loanId);
|
||||
if (!CollectionUtils.isEmpty(currentLoanRepayments)) {
|
||||
loanRepayments = currentLoanRepayments;
|
||||
loanRepaymentsCount = loanRepayments.size();
|
||||
if (responseParameters.contains("transactions")) {
|
||||
Collection<LoanTransactionNewData> currentLoanRepayments = this.loanReadPlatformService.retrieveLoanTransactions(loanId);
|
||||
if (!CollectionUtils.isEmpty(currentLoanRepayments)) {
|
||||
loanRepayments = currentLoanRepayments;
|
||||
loanRepaymentsCount = loanRepayments.size();
|
||||
}
|
||||
}
|
||||
|
||||
if (responseParameters.contains("repaymentSchedule")) {
|
||||
|
||||
DisbursementData singleDisbursement = loanBasicDetails.toDisburementData();
|
||||
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, loanBasicDetails.getCurrency(),
|
||||
singleDisbursement, loanBasicDetails.getTotalDisbursementCharges(), loanBasicDetails.getInArrearsTolerance());
|
||||
@@ -275,7 +277,8 @@ public class LoansApiResource {
|
||||
repaymentSchedule, loanRepayments, permissions, charges,
|
||||
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions,
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers);
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers);
|
||||
|
||||
return this.apiJsonSerializerService.serializeLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount);
|
||||
}
|
||||
@@ -302,7 +305,7 @@ public class LoansApiResource {
|
||||
|
||||
private String calculateLoanSchedule(final UriInfo uriInfo, final CalculateLoanScheduleCommand command) {
|
||||
|
||||
final LoanScheduleNewData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(command);
|
||||
final LoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(command);
|
||||
|
||||
final Set<String> typicalLoanScheduleResponseParameters = new HashSet<String>(
|
||||
Arrays.asList("periods", "cumulativePrincipalDisbursed"));
|
||||
@@ -406,26 +409,24 @@ public class LoansApiResource {
|
||||
@QueryParam("command") final String commandParam,
|
||||
final String jsonRequestBody) {
|
||||
|
||||
final LoanTransactionCommand command = this.apiDataConversionService
|
||||
.convertJsonToLoanTransactionCommand(loanId, jsonRequestBody);
|
||||
|
||||
Response response = null;
|
||||
final LoanTransactionCommand command = this.apiDataConversionService.convertJsonToLoanTransactionCommand(loanId, jsonRequestBody);
|
||||
|
||||
EntityIdentifier identifier = null;
|
||||
if (is(commandParam, "repayment")) {
|
||||
EntityIdentifier identifier = this.loanWritePlatformService
|
||||
.makeLoanRepayment(command);
|
||||
response = Response.ok().entity(identifier).build();
|
||||
identifier = this.loanWritePlatformService.makeLoanRepayment(command);
|
||||
} else if (is(commandParam, "waiveinterest")) {
|
||||
EntityIdentifier identifier = this.loanWritePlatformService
|
||||
.waiveInterestOnLoan(command);
|
||||
response = Response.ok().entity(identifier).build();
|
||||
identifier = this.loanWritePlatformService.waiveInterestOnLoan(command);
|
||||
} else if (is(commandParam, "writeoff")) {
|
||||
identifier = this.loanWritePlatformService.writeOff(command);
|
||||
} else if (is(commandParam, "closeasrescheduled")) {
|
||||
identifier = this.loanWritePlatformService.closeAsRescheduled(command);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
if (identifier == null) {
|
||||
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||
}
|
||||
|
||||
return response;
|
||||
return Response.ok().entity(identifier).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -440,8 +441,8 @@ public class LoansApiResource {
|
||||
LoanTransactionData transactionData = null;
|
||||
if (is(commandParam, "repayment")) {
|
||||
Set<String> typicalResponseParameters = new HashSet<String>(
|
||||
Arrays.asList("id", "transactionType", "date", "principal", "interest", "total", "totalWaived", "overpaid")
|
||||
);
|
||||
Arrays.asList("id", "transactionType", "date", "principal",
|
||||
"interest", "total", "totalWaived", "overpaid"));
|
||||
|
||||
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
if (responseParameters.isEmpty()) {
|
||||
@@ -460,7 +461,29 @@ public class LoansApiResource {
|
||||
}
|
||||
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
|
||||
|
||||
LoanTransactionNewData newTransactionData = this.loanReadPlatformService.retrieveNewLoanWaiveInterestDetails(loanId);
|
||||
final LoanTransactionNewData newTransactionData = this.loanReadPlatformService.retrieveNewLoanWaiveInterestDetails(loanId);
|
||||
return this.apiJsonSerializerService.serializeLoanTransactionDataToJson(prettyPrint, responseParameters, newTransactionData);
|
||||
} else if (is(commandParam, "writeoff")) {
|
||||
final Set<String> typicalResponseParameters = new HashSet<String>(Arrays.asList("id", "type", "date", "currency", "amount"));
|
||||
|
||||
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
if (responseParameters.isEmpty()) {
|
||||
responseParameters.addAll(typicalResponseParameters);
|
||||
}
|
||||
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
|
||||
|
||||
final LoanTransactionNewData newTransactionData = this.loanReadPlatformService.retrieveNewClosureDetails();
|
||||
return this.apiJsonSerializerService.serializeLoanTransactionDataToJson(prettyPrint, responseParameters, newTransactionData);
|
||||
} else if (is(commandParam, "closeasrescheduled")) {
|
||||
final Set<String> typicalResponseParameters = new HashSet<String>(Arrays.asList("id", "type", "date", "currency", "amount"));
|
||||
|
||||
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
if (responseParameters.isEmpty()) {
|
||||
responseParameters.addAll(typicalResponseParameters);
|
||||
}
|
||||
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
|
||||
|
||||
final LoanTransactionNewData newTransactionData = this.loanReadPlatformService.retrieveNewClosureDetails();
|
||||
return this.apiJsonSerializerService.serializeLoanTransactionDataToJson(prettyPrint, responseParameters, newTransactionData);
|
||||
} else {
|
||||
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing loan account data.
|
||||
@@ -55,8 +55,8 @@ public class LoanAccountData {
|
||||
private final LocalDate lifeCycleStatusDate;
|
||||
|
||||
// associations
|
||||
private final LoanScheduleNewData repaymentSchedule;
|
||||
private final Collection<LoanRepaymentTransactionData> loanRepayments;
|
||||
private final LoanScheduleData repaymentSchedule;
|
||||
private final Collection<LoanTransactionNewData> transactions;
|
||||
private final Collection<LoanChargeData> charges;
|
||||
private final LoanPermissionData permissions;
|
||||
private final LoanConvenienceData convenienceData;
|
||||
@@ -78,8 +78,8 @@ public class LoanAccountData {
|
||||
public LoanAccountData(
|
||||
final LoanBasicDetailsData basicDetails,
|
||||
final boolean convenienceDataRequired,
|
||||
final LoanScheduleNewData repaymentSchedule,
|
||||
final Collection<LoanRepaymentTransactionData> loanRepayments,
|
||||
final LoanScheduleData repaymentSchedule,
|
||||
final Collection<LoanTransactionNewData> transactions,
|
||||
final LoanPermissionData permissions,
|
||||
final Collection<LoanChargeData> charges,
|
||||
final Collection<LoanProductLookup> productOptions,
|
||||
@@ -95,7 +95,7 @@ public class LoanAccountData {
|
||||
final ChargeData chargeTemplate,
|
||||
final Collection<StaffData> loanOfficerOptions) {
|
||||
this.repaymentSchedule = repaymentSchedule;
|
||||
this.loanRepayments = loanRepayments;
|
||||
this.transactions = transactions;
|
||||
this.permissions = permissions;
|
||||
this.charges = charges;
|
||||
this.productOptions = productOptions;
|
||||
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
package org.mifosng.platform.api.data;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* This data object replaces {@link LoanTransactionData}.
|
||||
*/
|
||||
public class LoanRepaymentTransactionData {
|
||||
|
||||
private Long id;
|
||||
private EnumOptionData transactionType;
|
||||
private LocalDate date;
|
||||
private MoneyData total;
|
||||
|
||||
public LoanRepaymentTransactionData() {
|
||||
//
|
||||
}
|
||||
|
||||
public LoanRepaymentTransactionData(Long id, EnumOptionData transactionType,
|
||||
final LocalDate date, final MoneyData total) {
|
||||
this.id = id;
|
||||
this.transactionType = transactionType;
|
||||
this.date = date;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public EnumOptionData getTransactionType() {
|
||||
return transactionType;
|
||||
}
|
||||
|
||||
public void setTransactionType(EnumOptionData transactionType) {
|
||||
this.transactionType = transactionType;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public MoneyData getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(MoneyData total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
}
|
||||
+42
-10
@@ -9,7 +9,6 @@ import org.joda.time.LocalDate;
|
||||
* Immutable data object that represents a period of a loan schedule.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LoanSchedulePeriodData {
|
||||
|
||||
private final Integer period;
|
||||
@@ -17,26 +16,37 @@ public class LoanSchedulePeriodData {
|
||||
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 chargesDue;
|
||||
private final BigDecimal chargesPaid;
|
||||
private final BigDecimal chargesOutstanding;
|
||||
|
||||
@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;
|
||||
|
||||
@@ -54,32 +64,34 @@ public class LoanSchedulePeriodData {
|
||||
final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principalDue,
|
||||
final BigDecimal principalOutstanding, final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal totalDueForPeriod) {
|
||||
|
||||
BigDecimal principalDisbursed = null;
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, principalDue, principalOutstanding, interestDueOnPrincipalOutstanding, totalDueForPeriod);
|
||||
}
|
||||
|
||||
public static LoanSchedulePeriodData repaymentPeriodWithPayments(
|
||||
final Long loanId,
|
||||
@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 totalDueForPeriod,
|
||||
final BigDecimal totalPaid,
|
||||
final BigDecimal totalWaived,
|
||||
final BigDecimal totalWrittenOff,
|
||||
final BigDecimal totalOutstanding) {
|
||||
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate,
|
||||
principalOriginalDue, principalPaid, principalOutstanding, outstandingPrincipalBalanceOfLoan,
|
||||
interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestOutstanding,
|
||||
totalDueForPeriod, totalPaid, totalWaived, totalOutstanding);
|
||||
principalOriginalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan,
|
||||
interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestWrittenOff, interestOutstanding,
|
||||
totalDueForPeriod, totalPaid, totalWaived, totalWrittenOff, totalOutstanding);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -96,7 +108,7 @@ public class LoanSchedulePeriodData {
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(fromDate, dueDate).getDays();
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
@@ -104,6 +116,7 @@ public class LoanSchedulePeriodData {
|
||||
this.principalOriginalDue = null;
|
||||
this.principalDue = null;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = null;
|
||||
this.principalLoanBalanceOutstanding = principalDisbursed;
|
||||
|
||||
@@ -111,6 +124,7 @@ public class LoanSchedulePeriodData {
|
||||
this.interestDue = null;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = null;
|
||||
|
||||
this.chargesDue = chargesDueAtTimeOfDisbursement;
|
||||
@@ -126,6 +140,7 @@ public class LoanSchedulePeriodData {
|
||||
this.totalDueForPeriod = chargesDueAtTimeOfDisbursement;
|
||||
this.totalPaidForPeriod = this.chargesPaid;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = this.chargesOutstanding;
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
@@ -146,7 +161,7 @@ public class LoanSchedulePeriodData {
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(fromDate, dueDate).getDays();
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
@@ -154,6 +169,7 @@ public class LoanSchedulePeriodData {
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = principalOriginalDue;
|
||||
this.principalLoanBalanceOutstanding = principalOutstanding;
|
||||
|
||||
@@ -161,6 +177,7 @@ public class LoanSchedulePeriodData {
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = interestDueOnPrincipalOutstanding;
|
||||
|
||||
this.chargesDue = BigDecimal.ZERO;
|
||||
@@ -171,6 +188,7 @@ public class LoanSchedulePeriodData {
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = BigDecimal.ZERO;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = totalDueForPeriod;
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
@@ -188,21 +206,24 @@ public class LoanSchedulePeriodData {
|
||||
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 interestWaived,
|
||||
final BigDecimal interestWrittenOff,
|
||||
final BigDecimal interestOutstanding,
|
||||
final BigDecimal totalDueForPeriod,
|
||||
final BigDecimal totalPaid,
|
||||
final BigDecimal totalWaived,
|
||||
final BigDecimal totalWrittenOff,
|
||||
final BigDecimal totalOutstanding) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Days.daysBetween(fromDate, dueDate).getDays();
|
||||
this.daysInPeriod = Days.daysBetween(this.fromDate, this.dueDate).getDays();
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
@@ -210,6 +231,7 @@ public class LoanSchedulePeriodData {
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = principalPaid;
|
||||
this.principalWrittenOff = principalWrittenOff;
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
this.principalLoanBalanceOutstanding = principalLoanBalanceOutstanding;
|
||||
|
||||
@@ -217,6 +239,7 @@ public class LoanSchedulePeriodData {
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = interestPaid;
|
||||
this.interestWaived = interestWaived;
|
||||
this.interestWrittenOff = interestWrittenOff;
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
|
||||
this.chargesDue = BigDecimal.ZERO;
|
||||
@@ -227,6 +250,7 @@ public class LoanSchedulePeriodData {
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = totalPaid;
|
||||
this.totalWaivedForPeriod = totalWaived;
|
||||
this.totalWrittenOffForPeriod = totalWrittenOff;
|
||||
this.totalOutstandingForPeriod = totalOutstanding;
|
||||
|
||||
if (dueDate.isBefore(new LocalDate())) {
|
||||
@@ -276,6 +300,10 @@ public class LoanSchedulePeriodData {
|
||||
return defaultToZeroIfNull(this.principalPaid);
|
||||
}
|
||||
|
||||
public BigDecimal principalWrittenOff() {
|
||||
return defaultToZeroIfNull(this.principalWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal principalOutstanding() {
|
||||
return defaultToZeroIfNull(this.principalOutstanding);
|
||||
}
|
||||
@@ -291,6 +319,10 @@ public class LoanSchedulePeriodData {
|
||||
public BigDecimal interestWaived() {
|
||||
return defaultToZeroIfNull(this.interestWaived);
|
||||
}
|
||||
|
||||
public BigDecimal interestWrittenOff() {
|
||||
return defaultToZeroIfNull(this.interestWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal interestOutstanding() {
|
||||
return defaultToZeroIfNull(this.interestOutstanding);
|
||||
|
||||
+4
-2
@@ -25,11 +25,13 @@ public class LoanTransactionNewData {
|
||||
private BigDecimal amount;
|
||||
|
||||
public LoanTransactionNewData(
|
||||
final EnumOptionData transactionsType,
|
||||
final Long id,
|
||||
final EnumOptionData transactionType,
|
||||
final CurrencyData currency,
|
||||
final LocalDate date,
|
||||
final BigDecimal amount) {
|
||||
this.type = transactionsType;
|
||||
this.id = id;
|
||||
this.type = transactionType;
|
||||
this.currency = currency;
|
||||
this.date = date;
|
||||
this.amount = amount;
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package org.mifosng.platform.api.infrastructure;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.data.AdditionalFieldsSetData;
|
||||
import org.mifosng.platform.api.data.AppUserData;
|
||||
import org.mifosng.platform.api.data.AuthenticatedUserData;
|
||||
@@ -99,7 +99,7 @@ public interface ApiJsonSerializerService {
|
||||
|
||||
String serializeNoteDataToJson(boolean prettyPrint, Set<String> responseParameters, NoteData note);
|
||||
|
||||
String serializeLoanScheduleDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanScheduleNewData loanSchedule);
|
||||
String serializeLoanScheduleDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanScheduleData loanSchedule);
|
||||
|
||||
String serializeLoanAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanAccountData loanAccount);
|
||||
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.data.AdditionalFieldsSetData;
|
||||
import org.mifosng.platform.api.data.AppUserData;
|
||||
import org.mifosng.platform.api.data.AuthenticatedUserData;
|
||||
@@ -172,7 +172,7 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
|
||||
"closedOnDate", "expectedMaturityDate",
|
||||
"status",
|
||||
"lifeCycleStatusDate", "repaymentSchedule",
|
||||
"loanRepayments", "permissions", "convenienceData", "charges",
|
||||
"transactions", "permissions", "convenienceData", "charges",
|
||||
"productOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
|
||||
"repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions",
|
||||
"loanOfficerId", "loanOfficerName", "loanOfficerOptions", "chargeTemplate"));
|
||||
@@ -535,7 +535,7 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serializeLoanScheduleDataToJson(final boolean prettyPrint, final Set<String> responseParameters, final LoanScheduleNewData loanSchedule) {
|
||||
public String serializeLoanScheduleDataToJson(final boolean prettyPrint, final Set<String> responseParameters, final LoanScheduleData loanSchedule) {
|
||||
final Gson gsonDeserializer = helper
|
||||
.createGsonBuilderWithParameterExclusionSerializationStrategy(LOAN_SCHEDULE_DATA_PARAMETERS, prettyPrint, responseParameters);
|
||||
return helper.serializedJsonFrom(gsonDeserializer, loanSchedule);
|
||||
|
||||
+32
-4
@@ -23,7 +23,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
*/
|
||||
@Override
|
||||
public void handleTransaction(
|
||||
final List<LoanTransaction> repaymentsOrWaivers,
|
||||
final List<LoanTransaction> transactionsPostDisbursement,
|
||||
final MonetaryCurrency currency,
|
||||
final List<LoanRepaymentScheduleInstallment> installments) {
|
||||
|
||||
@@ -31,10 +31,15 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
currentInstallment.resetDerivedComponents();
|
||||
}
|
||||
|
||||
for (LoanTransaction loanTransaction : repaymentsOrWaivers) {
|
||||
for (LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||
|
||||
loanTransaction.resetDerivedComponents();
|
||||
handleTransaction(loanTransaction, currency, installments);
|
||||
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver()) {
|
||||
loanTransaction.resetDerivedComponents();
|
||||
handleTransaction(loanTransaction, currency, installments);
|
||||
} else if (loanTransaction.isWriteOff()) {
|
||||
loanTransaction.resetDerivedComponents();
|
||||
handleWriteOff(loanTransaction, currency, installments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +81,29 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
onLoanOverpayment(loanTransaction, transactionAmountUnprocessed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleWriteOff(
|
||||
final LoanTransaction loanTransaction,
|
||||
final MonetaryCurrency currency,
|
||||
final List<LoanRepaymentScheduleInstallment> installments) {
|
||||
|
||||
final Money interestWaivedPortion = Money.zero(currency);
|
||||
Money principalPortion = Money.zero(currency);
|
||||
Money interestPortion = Money.zero(currency);
|
||||
Money chargesPortion = Money.zero(currency);
|
||||
|
||||
// determine how much is written off in total and breakdown for principal, interest and charges
|
||||
for (LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||
|
||||
if (currentInstallment.isNotFullyCompleted()) {
|
||||
principalPortion = principalPortion.plus(currentInstallment.writeOffOutstandingPrincipal(currency));
|
||||
interestPortion = interestPortion.plus(currentInstallment.writeOffOutstandingInterest(currency));
|
||||
}
|
||||
}
|
||||
|
||||
loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, interestWaivedPortion, chargesPortion);
|
||||
}
|
||||
|
||||
// abstract interface
|
||||
/**
|
||||
|
||||
+2
-2
@@ -68,7 +68,7 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLo
|
||||
Money interestWaivedPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money chargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
|
||||
if (loanTransaction.isWaiver()) {
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
interestWaivedPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestWaivedPortion);
|
||||
|
||||
@@ -135,7 +135,7 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLo
|
||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money chargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
|
||||
if (loanTransaction.isWaiver()) {
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
interestWaivedPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestWaivedPortion);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends
|
||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money chargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
|
||||
if (loanTransaction.isWaiver()) {
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
interestWaivedPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestWaivedPortion);
|
||||
} else {
|
||||
|
||||
+8
-8
@@ -53,7 +53,7 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
||||
}
|
||||
break;
|
||||
case LOAN_REPAYMENT_OR_WAIVER:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.CLOSED, LoanStatus.OVERPAID)) {
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.OVERPAID)) {
|
||||
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses);
|
||||
} else {
|
||||
newState = from;
|
||||
@@ -61,26 +61,26 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
||||
break;
|
||||
case REPAID_IN_FULL:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses);
|
||||
newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_WRITE_OFF:
|
||||
case WRITE_OFF_OUTSTANDING:
|
||||
if (this.anyOfAllowedWhenComingFrom(from,LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses);
|
||||
newState = stateOf(LoanStatus.CLOSED_WRITTEN_OFF, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_RESCHEDULE:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses);
|
||||
newState = stateOf(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case INTERST_REBATE_OWED:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED)) {
|
||||
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses);
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_OVERPAYMENT:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED, LoanStatus.ACTIVE)) {
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.OVERPAID, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
|
||||
+2
-2
@@ -73,7 +73,7 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money chargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
|
||||
if (loanTransaction.isWaiver()) {
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
interestWaivedPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestWaivedPortion);
|
||||
} else {
|
||||
@@ -116,7 +116,7 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money chargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
|
||||
if (loanTransaction.isWaiver()) {
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
interestWaivedPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestWaivedPortion);
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.commands.LoanApplicationCommand;
|
||||
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
|
||||
import org.mifosng.platform.client.domain.Client;
|
||||
@@ -282,7 +282,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
public void modifyLoanApplication(final LoanApplicationCommand command, final Client client, final LoanProduct loanProduct,
|
||||
final Fund fund, final LoanTransactionProcessingStrategy strategy, final LoanScheduleNewData modifiedLoanSchedule, final Set<LoanCharge> charges,
|
||||
final Fund fund, final LoanTransactionProcessingStrategy strategy, final LoanScheduleData modifiedLoanSchedule, final Set<LoanCharge> charges,
|
||||
final Staff loanOfficer) {
|
||||
|
||||
if (command.isClientChanged()) {
|
||||
@@ -361,7 +361,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
// if the loan application/contract is modified when repayments are already against it - then need to re-process it
|
||||
final List<LoanTransaction> repaymentsOrWaivers = retreiveListOfRepaymentOrWaiverTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> repaymentsOrWaivers = retreiveListOfTransactionsPostDisbursement();
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy);
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(repaymentsOrWaivers, getCurrency(), this.repaymentScheduleInstallments);
|
||||
@@ -617,7 +617,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||
final LoanTransaction adjustedTransaction) {
|
||||
|
||||
LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, LoanStatus.fromInt(this.loanStatus));
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, LoanStatus.fromInt(this.loanStatus));
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
|
||||
loanTransaction.updateLoan(this);
|
||||
@@ -626,7 +626,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
this.loanTransactions.add(loanTransaction);
|
||||
|
||||
if (loanTransaction.isNotRepayment() && loanTransaction.isNotWaiver()) {
|
||||
if (loanTransaction.isNotRepayment() && loanTransaction.isNotInterestWaiver()) {
|
||||
final String errorMessage = "A transaction of type repayment or waiver was expected but not received.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction",
|
||||
"is.not.a.repayment.or.waiver.transaction", errorMessage);
|
||||
@@ -647,7 +647,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
"cannot.be.a.future.date", errorMessage, loanTransactionDate);
|
||||
}
|
||||
|
||||
if (loanTransaction.isWaiver()) {
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
Money totalInterestOutstandingOnLoan = getTotalInterestOutstandingOnLoan();
|
||||
if (adjustedTransaction != null) {
|
||||
totalInterestOutstandingOnLoan = totalInterestOutstandingOnLoan.plus(adjustedTransaction.getAmount());
|
||||
@@ -663,14 +663,14 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (isTransactionChronologicallyLatest && adjustedTransaction == null) {
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(), this.repaymentScheduleInstallments);
|
||||
} else {
|
||||
final List<LoanTransaction> repaymentsOrWaivers = retreiveListOfRepaymentOrWaiverTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> repaymentsOrWaivers = retreiveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(repaymentsOrWaivers, getCurrency(), this.repaymentScheduleInstallments);
|
||||
}
|
||||
|
||||
doPostLoanTransactionChecks(loanTransaction, loanLifecycleStateMachine);
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfRepaymentOrWaiverTransactionsPostDisbursement() {
|
||||
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() {
|
||||
List<LoanTransaction> repaymentsOrWaivers = new ArrayList<LoanTransaction>();
|
||||
for (LoanTransaction transaction : this.loanTransactions) {
|
||||
if (!transaction.isDisbursement() && transaction.isNotContra()) {
|
||||
@@ -738,6 +738,26 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
return isChronologicallyLatestRepaymentOrWaiver;
|
||||
}
|
||||
|
||||
private boolean isChronologicallyLatestTransaction(
|
||||
final LoanTransaction loanTransaction,
|
||||
final List<LoanTransaction> loanTransactions) {
|
||||
|
||||
boolean isChronologicallyLatestRepaymentOrWaiver = true;
|
||||
|
||||
LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
|
||||
for (LoanTransaction previousTransaction : loanTransactions) {
|
||||
if (previousTransaction.isNotContra()) {
|
||||
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) ||
|
||||
currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) {
|
||||
isChronologicallyLatestRepaymentOrWaiver = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isChronologicallyLatestRepaymentOrWaiver;
|
||||
}
|
||||
|
||||
public LocalDate possibleNextRepaymentDate() {
|
||||
LocalDate earliestUnpaidInstallmentDate = new LocalDate();
|
||||
@@ -770,7 +790,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
|
||||
if (installment.isNotFullyCompleted()) {
|
||||
possibleNextRepaymentAmount = installment.getTotalDue(currency);
|
||||
possibleNextRepaymentAmount = installment.getTotalOutstanding(currency);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -805,14 +825,20 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
final LoanTransaction newTransactionDetail,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
|
||||
if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotWaiver()) {
|
||||
final String errorMessage = "A transaction of type repayment or waiver was expected but not received.";
|
||||
if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotInterestWaiver()) {
|
||||
final String errorMessage = "Only transactions of type repayment or interest waiver can be adjusted.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction",
|
||||
"is.not.a.repayment.or.waiver.transaction", errorMessage);
|
||||
"adjustment.is.only.allowed.to.repayment.or.waiver.transaction", errorMessage);
|
||||
}
|
||||
|
||||
if (isClosed()) {
|
||||
final String errorMessage = "Transactions of a closed loan cannot be adjusted.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction",
|
||||
"adjustment.is.not.allowed.on.closed.loan", errorMessage);
|
||||
}
|
||||
|
||||
transactionForAdjustment.contra();
|
||||
if (newTransactionDetail.isRepayment() || newTransactionDetail.isWaiver()) {
|
||||
if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) {
|
||||
handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment);
|
||||
}
|
||||
}
|
||||
@@ -867,32 +893,49 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return this.loanRepaymentScheduleDetail.getCurrency();
|
||||
}
|
||||
|
||||
public void writeOff(final DateTime writtenOffOn,
|
||||
public LoanTransaction closeAsWrittenOff(
|
||||
final LocalDate writtenOffOnLocalDate,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
|
||||
LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_WRITE_OFF, LoanStatus.fromInt(this.loanStatus));
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING, LoanStatus.fromInt(this.loanStatus));
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
|
||||
this.closedOnDate = writtenOffOn.toDate();
|
||||
this.writtenOffOnDate = writtenOffOn.toDate();
|
||||
this.closedOnDate = writtenOffOnLocalDate.toDate();
|
||||
this.writtenOffOnDate = writtenOffOnLocalDate.toDate();
|
||||
|
||||
LocalDate writtenOffOnLocalDate = new LocalDate(writtenOffOnDate);
|
||||
if (writtenOffOnLocalDate.isBefore(this.getDisbursementDate())) {
|
||||
final String errorMessage = "The date on which a loan is withdrawn cannot be before the loan disbursement date: "
|
||||
final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: "
|
||||
+ getDisbursementDate().toString();
|
||||
throw new InvalidLoanStateTransitionException("writeoff",
|
||||
"cannot.be.before.submittal.date", errorMessage,
|
||||
writtenOffOnLocalDate, getDisbursementDate());
|
||||
}
|
||||
|
||||
if (writtenOffOnLocalDate.isAfter(new LocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is written off cannot be in the future.";
|
||||
throw new InvalidLoanStateTransitionException("writeoff",
|
||||
"cannot.be.a.future.date", errorMessage,
|
||||
writtenOffOnLocalDate);
|
||||
}
|
||||
|
||||
final LoanTransaction loanTransaction = LoanTransaction.writeoff(this, writtenOffOnLocalDate);
|
||||
boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions);
|
||||
if (!isLastTransaction) {
|
||||
final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions.";
|
||||
throw new InvalidLoanStateTransitionException("writeoff","must.occur.on.or.after.other.transaction.dates", errorMessage, writtenOffOnLocalDate);
|
||||
}
|
||||
|
||||
this.loanTransactions.add(loanTransaction);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy);
|
||||
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), this.repaymentScheduleInstallments);
|
||||
|
||||
return loanTransaction;
|
||||
}
|
||||
|
||||
public void reschedule(final DateTime rescheduledOn,
|
||||
// FIXME - KW - finish off reschedule/restructure capability for loans.
|
||||
public void reschedule(
|
||||
final DateTime rescheduledOn,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
|
||||
LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE, LoanStatus.fromInt(this.loanStatus));
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
package org.mifosng.platform.loan.domain;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public enum LoanEvent {
|
||||
|
||||
LOAN_CREATED, LOAN_REJECTED, LOAN_WITHDRAWN, LOAN_APPROVED, LOAN_APPROVAL_UNDO, LOAN_DISBURSED, LOAN_DISBURSAL_UNDO, LOAN_REPAYMENT_OR_WAIVER,
|
||||
//
|
||||
REPAID_IN_FULL, LOAN_WRITE_OFF, LOAN_RESCHEDULE, INTERST_REBATE_OWED, LOAN_OVERPAYMENT;
|
||||
LOAN_CREATED, //
|
||||
LOAN_REJECTED, //
|
||||
LOAN_WITHDRAWN, //
|
||||
LOAN_APPROVED, //
|
||||
LOAN_APPROVAL_UNDO, //
|
||||
LOAN_DISBURSED, //
|
||||
LOAN_DISBURSAL_UNDO, //
|
||||
LOAN_REPAYMENT_OR_WAIVER, //
|
||||
REPAID_IN_FULL, //
|
||||
WRITE_OFF_OUTSTANDING, //
|
||||
LOAN_RESCHEDULE, //
|
||||
INTERST_REBATE_OWED, //
|
||||
LOAN_OVERPAYMENT;
|
||||
}
|
||||
|
||||
+45
-18
@@ -19,7 +19,7 @@ import org.mifosng.platform.user.domain.AppUser;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_repayment_schedule")
|
||||
public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id")
|
||||
@@ -37,11 +37,17 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
|
||||
@Column(name = "principal_completed_derived", scale=6, precision=19)
|
||||
private BigDecimal principalCompleted = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "principal_writtenoff_derived", scale=6, precision=19)
|
||||
private BigDecimal principalWrittenOff = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "interest_completed_derived", scale = 6, precision = 19)
|
||||
private BigDecimal interestCompleted = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal interestWaived = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "interest_writtenoff_derived", scale=6, precision=19)
|
||||
private BigDecimal interestWrittenOff = BigDecimal.ZERO;
|
||||
|
||||
@Column(name="completed_derived")
|
||||
private boolean completed;
|
||||
@@ -93,8 +99,13 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
|
||||
return Money.of(currency, this.principalCompleted);
|
||||
}
|
||||
|
||||
public Money getPrincipalWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalWrittenOff);
|
||||
}
|
||||
|
||||
public Money getPrincipalOutstanding(final MonetaryCurrency currency) {
|
||||
return getPrincipal(currency).minus(getPrincipalCompleted(currency));
|
||||
final Money principalAccountedFor = getPrincipalCompleted(currency).plus(getPrincipalWrittenOff(currency));
|
||||
return getPrincipal(currency).minus(principalAccountedFor);
|
||||
}
|
||||
|
||||
public Money getInterest(final MonetaryCurrency currency) {
|
||||
@@ -109,15 +120,20 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
|
||||
return Money.of(currency, this.interestWaived);
|
||||
}
|
||||
|
||||
public Money getInterestWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestWrittenOff);
|
||||
}
|
||||
|
||||
public Money getInterestOutstanding(final MonetaryCurrency currency) {
|
||||
return getInterest(currency).minus(getInterestCompleted(currency).plus(getInterestWaived(currency)));
|
||||
final Money interestAccountedFor = getInterestCompleted(currency).plus(getInterestWaived(currency)).plus(getInterestWrittenOff(currency));
|
||||
return getInterest(currency).minus(interestAccountedFor);
|
||||
}
|
||||
|
||||
public boolean isInterestDue(final MonetaryCurrency currency) {
|
||||
return getInterest(currency).minus(getInterestCompleted(currency).plus(getInterestWaived(currency))).isGreaterThanZero();
|
||||
return getInterestOutstanding(currency).isGreaterThanZero();
|
||||
}
|
||||
|
||||
public Money getTotal(final MonetaryCurrency currency) {
|
||||
public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) {
|
||||
return getPrincipal(currency).plus(getInterest(currency));
|
||||
}
|
||||
|
||||
@@ -142,22 +158,15 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
|
||||
}
|
||||
|
||||
public boolean isPrincipalCompleted(final MonetaryCurrency currency) {
|
||||
return getPrincipal(currency).minus(getPrincipalCompleted(currency)).isZero();
|
||||
}
|
||||
|
||||
public Money getTotalDue(MonetaryCurrency currency) {
|
||||
final Money totalPaidOrWaived = getInterestWaived(currency).plus(getTotalCompleted(currency));
|
||||
return getTotal(currency).minus(totalPaidOrWaived);
|
||||
}
|
||||
|
||||
private Money getTotalCompleted(MonetaryCurrency currency) {
|
||||
return getPrincipalCompleted(currency).plus(getInterestCompleted(currency));
|
||||
return getPrincipalOutstanding(currency).isZero();
|
||||
}
|
||||
|
||||
public void resetDerivedComponents() {
|
||||
this.principalCompleted = BigDecimal.ZERO;
|
||||
this.principalWrittenOff = BigDecimal.ZERO;
|
||||
this.interestCompleted = BigDecimal.ZERO;
|
||||
this.interestWaived = BigDecimal.ZERO;
|
||||
this.interestWrittenOff = BigDecimal.ZERO;
|
||||
this.completed = false;
|
||||
}
|
||||
|
||||
@@ -175,7 +184,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
|
||||
interestPortionOfTransaction = interestPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.completed = getTotalDue(currency).isZero();
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
return interestPortionOfTransaction;
|
||||
}
|
||||
@@ -194,7 +203,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
|
||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.completed = getTotalDue(currency).isZero();
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
return principalPortionOfTransaction;
|
||||
}
|
||||
@@ -212,10 +221,28 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
|
||||
waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.completed = getTotalDue(currency).isZero();
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
return waivedInterestPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money writeOffOutstandingPrincipal(final MonetaryCurrency currency) {
|
||||
|
||||
final Money principalDue = getPrincipalOutstanding(currency);
|
||||
this.principalWrittenOff = principalDue.getAmount();
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
return principalDue;
|
||||
}
|
||||
|
||||
public Money writeOffOutstandingInterest(final MonetaryCurrency currency) {
|
||||
|
||||
final Money interestDue = getInterestOutstanding(currency);
|
||||
this.interestWrittenOff = interestDue.getAmount();
|
||||
this.completed = getTotalOutstanding(currency).isZero();
|
||||
|
||||
return interestDue;
|
||||
}
|
||||
|
||||
public boolean isOverdueOn(final LocalDate transactionDate) {
|
||||
return this.getDueDate().isBefore(transactionDate);
|
||||
|
||||
+4
@@ -10,4 +10,8 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
||||
|
||||
void handleTransaction(List<LoanTransaction> repaymentsOrWaivers, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
||||
|
||||
void handleWriteOff(LoanTransaction loanTransaction,
|
||||
MonetaryCurrency loanCurrency,
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
||||
|
||||
}
|
||||
@@ -11,7 +11,9 @@ public enum LoanStatus {
|
||||
ACTIVE(300, "loanStatusType.active"), //
|
||||
WITHDRAWN_BY_CLIENT(400, "loanStatusType.withdrawn.by.client"), //
|
||||
REJECTED(500, "loanStatusType.rejected"), //
|
||||
CLOSED(600, "loanStatusType.closed"), //
|
||||
CLOSED_OBLIGATIONS_MET(600, "loanStatusType.closed.obligations.met"), //
|
||||
CLOSED_WRITTEN_OFF(601, "loanStatusType.closed.written.off"), //
|
||||
CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT(602, "loanStatusType.closed.reschedule.outstanding.amount"), //
|
||||
OVERPAID(700, "loanStatusType.overpaid");
|
||||
|
||||
private final Integer value;
|
||||
@@ -37,7 +39,13 @@ public enum LoanStatus {
|
||||
enumeration = LoanStatus.REJECTED;
|
||||
break;
|
||||
case 600:
|
||||
enumeration = LoanStatus.CLOSED;
|
||||
enumeration = LoanStatus.CLOSED_OBLIGATIONS_MET;
|
||||
break;
|
||||
case 601:
|
||||
enumeration = LoanStatus.CLOSED_WRITTEN_OFF;
|
||||
break;
|
||||
case 602:
|
||||
enumeration = LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT;
|
||||
break;
|
||||
case 700:
|
||||
enumeration = LoanStatus.OVERPAID;
|
||||
@@ -76,9 +84,21 @@ public enum LoanStatus {
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return this.value.equals(LoanStatus.CLOSED.getValue());
|
||||
return isClosedObligationsMet() || isClosedWrittenOff() || isClosedWithOutsandingAmountMarkedForReschedule();
|
||||
}
|
||||
|
||||
public boolean isClosedObligationsMet() {
|
||||
return this.value.equals(LoanStatus.CLOSED_OBLIGATIONS_MET.getValue());
|
||||
}
|
||||
|
||||
public boolean isClosedWrittenOff() {
|
||||
return this.value.equals(LoanStatus.CLOSED_WRITTEN_OFF.getValue());
|
||||
}
|
||||
|
||||
public boolean isClosedWithOutsandingAmountMarkedForReschedule() {
|
||||
return this.value.equals(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT.getValue());
|
||||
}
|
||||
|
||||
public boolean isWithdrawnByClient() {
|
||||
return this.value.equals(LoanStatus.WITHDRAWN_BY_CLIENT.getValue());
|
||||
}
|
||||
|
||||
+25
-11
@@ -35,7 +35,7 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
||||
private Loan loan;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private final BigDecimal amount;
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "principal_portion_derived", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal principalPortion = BigDecimal.ZERO;
|
||||
@@ -63,7 +63,6 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
protected LoanTransaction() {
|
||||
this.loan = null;
|
||||
this.amount = null;
|
||||
this.dateOf = null;
|
||||
this.typeOf = null;
|
||||
}
|
||||
@@ -81,15 +80,19 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
public static LoanTransaction waiver(final Loan loan, final Money waived, final LocalDate waiveDate) {
|
||||
return new LoanTransaction(loan, LoanTransactionType.WAIVED, waived.getAmount(), waiveDate);
|
||||
return new LoanTransaction(loan, LoanTransactionType.WAIVE_INTEREST, waived.getAmount(), waiveDate);
|
||||
}
|
||||
|
||||
private static LoanTransaction contra(final LoanTransaction originalTransaction) {
|
||||
LoanTransaction contra = new LoanTransaction(null, LoanTransactionType.REVERSAL, originalTransaction.getAmount().negate(), new LocalDate(originalTransaction.getDateOf()));
|
||||
LoanTransaction contra = new LoanTransaction(null, LoanTransactionType.CONTRA, originalTransaction.getAmount().negate(), new LocalDate(originalTransaction.getDateOf()));
|
||||
contra.updateContra(originalTransaction);
|
||||
return contra;
|
||||
}
|
||||
|
||||
public static LoanTransaction writeoff(final Loan loan, final LocalDate writeOffDate) {
|
||||
return new LoanTransaction(loan, LoanTransactionType.WRITEOFF, null, writeOffDate);
|
||||
}
|
||||
|
||||
public void updateContra(final LoanTransaction transaction) {
|
||||
this.contra = transaction;
|
||||
}
|
||||
@@ -142,23 +145,27 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf());
|
||||
}
|
||||
|
||||
public boolean isWaiver() {
|
||||
return LoanTransactionType.WAIVED.equals(getTypeOf()) && isNotContra();
|
||||
public boolean isInterestWaiver() {
|
||||
return LoanTransactionType.WAIVE_INTEREST.equals(getTypeOf()) && isNotContra();
|
||||
}
|
||||
|
||||
public boolean isNotWaiver() {
|
||||
return !isWaiver();
|
||||
public boolean isNotInterestWaiver() {
|
||||
return !isInterestWaiver();
|
||||
}
|
||||
|
||||
public boolean isWriteOff() {
|
||||
return getTypeOf().isWriteOff() && isNotContra();
|
||||
}
|
||||
|
||||
public boolean isIdentifiedBy(Long identifier) {
|
||||
public boolean isIdentifiedBy(final Long identifier) {
|
||||
return this.getId().equals(identifier);
|
||||
}
|
||||
|
||||
public boolean isBelongingToLoanOf(Loan check) {
|
||||
public boolean isBelongingToLoanOf(final Loan check) {
|
||||
return this.loan.getId().equals(check.getId());
|
||||
}
|
||||
|
||||
public boolean isNotBelongingToLoanOf(Loan check) {
|
||||
public boolean isNotBelongingToLoanOf(final Loan check) {
|
||||
return !isBelongingToLoanOf(check);
|
||||
}
|
||||
|
||||
@@ -187,6 +194,13 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.interestWaivedPortion = getInterestWaivedPortion(currency).plus(interestWaivedPortion).getAmount();
|
||||
this.chargesPortion = getChargesPortion(currency).plus(charges).getAmount();
|
||||
}
|
||||
|
||||
public void updateComponentsAndTotal(final Money principal, final Money interest, final Money interestWaivedPortion, final Money charges) {
|
||||
updateComponents(principal, interest, interestWaivedPortion, charges);
|
||||
|
||||
final MonetaryCurrency currency = principal.getCurrency();
|
||||
this.amount = getPrincipalPortion(currency).plus(getInterestPortion(currency)).plus(this.chargesPortion).getAmount();
|
||||
}
|
||||
|
||||
public Money getPrincipalPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, principalPortion);
|
||||
|
||||
+2
-2
@@ -13,9 +13,9 @@ public class LoanTransactionComparator implements Comparator<LoanTransaction> {
|
||||
final int comparsion = o1.getTransactionDate().compareTo(o2.getTransactionDate());
|
||||
if (comparsion == 0) {
|
||||
// equal transaction dates
|
||||
if (o1.isWaiver() && o2.isNotWaiver()) {
|
||||
if (o1.isInterestWaiver() && o2.isNotInterestWaiver()) {
|
||||
compareResult = -1;
|
||||
} else if (o1.isNotWaiver() && o2.isWaiver()) {
|
||||
} else if (o1.isNotInterestWaiver() && o2.isInterestWaiver()) {
|
||||
compareResult = 1;
|
||||
} else {
|
||||
compareResult = 0;
|
||||
|
||||
+21
-5
@@ -5,9 +5,15 @@ public enum LoanTransactionType {
|
||||
INVALID(0, "loanTransactionType.invalid"), //
|
||||
DISBURSEMENT(1, "loanTransactionType.disbursement"), //
|
||||
REPAYMENT(2, "loanTransactionType.repayment"), //
|
||||
REVERSAL(3, "loanTransactionType.reversal"), //
|
||||
WAIVED(4, "loanTransactionType.waiver"), //
|
||||
REPAYMENT_AT_DISBURSEMENT(5, "loanTransactionType.repaymentAtDisbursement");
|
||||
CONTRA(3, "loanTransactionType.contra"), //
|
||||
WAIVE_INTEREST(4, "loanTransactionType.waiver"), //
|
||||
REPAYMENT_AT_DISBURSEMENT(5, "loanTransactionType.repaymentAtDisbursement"), //
|
||||
WRITEOFF(6, "loanTransactionType.writeOff"),
|
||||
MARKED_FOR_RESCHEDULING(7, "loanTransactionType.marked.for.rescheduling"), //
|
||||
/**
|
||||
* This type of transactions is allowed on written-off loans where mfi still attempts to recover payments from applicant after writing-off.
|
||||
*/
|
||||
RECOVERY_REPAYMENT(8, "loanTransactionType.recoveryRepayment");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
@@ -40,18 +46,28 @@ public enum LoanTransactionType {
|
||||
loanTransactionType = LoanTransactionType.REPAYMENT;
|
||||
break;
|
||||
case 3:
|
||||
loanTransactionType = LoanTransactionType.REVERSAL;
|
||||
loanTransactionType = LoanTransactionType.CONTRA;
|
||||
break;
|
||||
case 4:
|
||||
loanTransactionType = LoanTransactionType.WAIVED;
|
||||
loanTransactionType = LoanTransactionType.WAIVE_INTEREST;
|
||||
break;
|
||||
case 5:
|
||||
loanTransactionType = LoanTransactionType.REPAYMENT_AT_DISBURSEMENT;
|
||||
break;
|
||||
case 6:
|
||||
loanTransactionType = LoanTransactionType.WRITEOFF;
|
||||
break;
|
||||
case 7:
|
||||
loanTransactionType = LoanTransactionType.MARKED_FOR_RESCHEDULING;
|
||||
break;
|
||||
default:
|
||||
loanTransactionType = LoanTransactionType.INVALID;
|
||||
break;
|
||||
}
|
||||
return loanTransactionType;
|
||||
}
|
||||
|
||||
public boolean isWriteOff() {
|
||||
return this.value.equals(LoanTransactionType.WRITEOFF.getValue());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends
|
||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money chargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
|
||||
if (loanTransaction.isWaiver()) {
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
interestWaivedPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestWaivedPortion);
|
||||
} else {
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
package org.mifosng.platform.loan.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
|
||||
|
||||
public interface CalculationPlatformService {
|
||||
|
||||
LoanScheduleNewData calculateLoanScheduleNew(CalculateLoanScheduleCommand command);
|
||||
LoanScheduleData calculateLoanScheduleNew(CalculateLoanScheduleCommand command);
|
||||
|
||||
/**
|
||||
* Not used at present from application.
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package org.mifosng.platform.loan.service;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.MoneyData;
|
||||
@@ -51,7 +51,7 @@ public class CalculationPlatformServiceImpl implements CalculationPlatformServic
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanScheduleNewData calculateLoanScheduleNew(final CalculateLoanScheduleCommand command) {
|
||||
public LoanScheduleData calculateLoanScheduleNew(final CalculateLoanScheduleCommand command) {
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.commands.LoanApplicationCommand;
|
||||
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
|
||||
import org.mifosng.platform.client.domain.Client;
|
||||
@@ -122,7 +122,7 @@ public class LoanAssembler {
|
||||
|
||||
loan.setExternalId(command.getExternalId());
|
||||
|
||||
final LoanScheduleNewData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(command.toCalculateLoanScheduleCommand());
|
||||
final LoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(command.toCalculateLoanScheduleCommand());
|
||||
|
||||
for (LoanSchedulePeriodData scheduledLoanInstallment : loanSchedule.getPeriods()) {
|
||||
if (scheduledLoanInstallment.isRepaymentPeriod()) {
|
||||
|
||||
+5
-4
@@ -3,12 +3,11 @@ package org.mifosng.platform.loan.service;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.DisbursementData;
|
||||
import org.mifosng.platform.api.data.LoanBasicDetailsData;
|
||||
import org.mifosng.platform.api.data.LoanPermissionData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionNewData;
|
||||
|
||||
@@ -16,9 +15,9 @@ public interface LoanReadPlatformService {
|
||||
|
||||
LoanBasicDetailsData retrieveLoanAccountDetails(Long loanId);
|
||||
|
||||
LoanScheduleNewData retrieveRepaymentSchedule(Long loanId, CurrencyData currency, DisbursementData disbursement, BigDecimal totalChargesAtDisbursement, BigDecimal inArrearsTolerance);
|
||||
LoanScheduleData retrieveRepaymentSchedule(Long loanId, CurrencyData currency, DisbursementData disbursement, BigDecimal totalChargesAtDisbursement, BigDecimal inArrearsTolerance);
|
||||
|
||||
Collection<LoanRepaymentTransactionData> retrieveLoanPayments(Long loanId);
|
||||
Collection<LoanTransactionNewData> retrieveLoanTransactions(Long loanId);
|
||||
|
||||
LoanPermissionData retrieveLoanPermissions(
|
||||
LoanBasicDetailsData loanBasicDetails, boolean isWaiverAllowed,
|
||||
@@ -33,4 +32,6 @@ public interface LoanReadPlatformService {
|
||||
LoanTransactionNewData retrieveNewLoanWaiveInterestDetails(Long loanId);
|
||||
|
||||
LoanTransactionData retrieveLoanTransactionDetails(Long loanId, Long transactionId);
|
||||
|
||||
LoanTransactionNewData retrieveNewClosureDetails();
|
||||
}
|
||||
+58
-39
@@ -7,7 +7,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.data.ClientData;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.DisbursementData;
|
||||
@@ -17,7 +17,6 @@ import org.mifosng.platform.api.data.LoanBasicDetailsData;
|
||||
import org.mifosng.platform.api.data.LoanChargeData;
|
||||
import org.mifosng.platform.api.data.LoanPermissionData;
|
||||
import org.mifosng.platform.api.data.LoanProductData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionNewData;
|
||||
@@ -97,7 +96,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanScheduleNewData retrieveRepaymentSchedule(final Long loanId,
|
||||
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
|
||||
final CurrencyData currency,
|
||||
final DisbursementData disbursement,
|
||||
final BigDecimal totalChargesAtDisbursement,
|
||||
@@ -123,10 +122,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
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 cumulativeChargesToDate = wrapper.deriveCumulativeChargesToDate();
|
||||
final BigDecimal cumulativeChargesPaid = wrapper.deriveCumulativeChargesPaid();
|
||||
@@ -136,6 +137,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final BigDecimal totalExpectedRepayment = cumulativePrincipalDisbursed.add(totalCostOfLoan);
|
||||
final BigDecimal totalPaidToDate = cumulativePrincipalPaid.add(cumulativeInterestPaid).add(cumulativeChargesPaid);
|
||||
final BigDecimal totalWaivedToDate = cumulativeInterestWaived;
|
||||
final BigDecimal totalWrittenOffToDate = cumulativePrincipalWrittenOff.add(cumulativeInterestWrittenOff);
|
||||
final BigDecimal totalOutstanding = cumulativePrincipalOutstanding.add(cumulativeInterestOutstanding).add(cumulativeChargesOutstanding);
|
||||
|
||||
final BigDecimal totalOverdue = wrapper.deriveCumulativeTotalOverdue();
|
||||
@@ -149,31 +151,29 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
totalInArrears = totalOverdueMoney.getAmount();
|
||||
}
|
||||
|
||||
return new LoanScheduleNewData(currency, periods, loanTermInDays,
|
||||
cumulativePrincipalDisbursed, cumulativePrincipalDue, cumulativePrincipalPaid, cumulativePrincipalOutstanding,
|
||||
cumulativeInterestExpected, cumulativeInterestPaid, cumulativeInterestWaived, cumulativeInterestOutstanding,
|
||||
return new LoanScheduleData(currency, periods, loanTermInDays,
|
||||
cumulativePrincipalDisbursed, cumulativePrincipalDue, cumulativePrincipalPaid, cumulativePrincipalWrittenOff, cumulativePrincipalOutstanding,
|
||||
cumulativeInterestExpected, cumulativeInterestPaid, cumulativeInterestWaived, cumulativeInterestWrittenOff, cumulativeInterestOutstanding,
|
||||
cumulativeChargesToDate, cumulativeChargesPaid, cumulativeChargesOutstanding,
|
||||
totalCostOfLoan, totalExpectedRepayment, totalPaidToDate, totalWaivedToDate, totalOutstanding, totalInArrears);
|
||||
totalCostOfLoan, totalExpectedRepayment, totalPaidToDate, totalWaivedToDate, totalWrittenOffToDate, totalOutstanding, totalInArrears);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
throw new LoanNotFoundException(loanId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanRepaymentTransactionData> retrieveLoanPayments(Long loanId) {
|
||||
public Collection<LoanTransactionNewData> retrieveLoanTransactions(final Long loanId) {
|
||||
try {
|
||||
context.authenticatedUser();
|
||||
|
||||
LoanPaymentsMapper rm = new LoanPaymentsMapper();
|
||||
LoanTransactionsMapper rm = new LoanTransactionsMapper();
|
||||
|
||||
// retrieve all loan transactions that are not invalid (0) and not
|
||||
// disbursements (1) and have not been 'contra'ed by another transaction
|
||||
// retrieve all loan transactions that are not invalid and have not been 'contra'ed by another transaction
|
||||
// repayments at time of disbursement (e.g. charges)
|
||||
String sql = "select "
|
||||
+ rm.LoanPaymentsSchema()
|
||||
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 1, 5) and tr.contra_id is null order by tr.transaction_date ASC";
|
||||
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and tr.contra_id is null order by tr.transaction_date ASC";
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
@@ -181,8 +181,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
@Override
|
||||
public LoanPermissionData retrieveLoanPermissions(
|
||||
LoanBasicDetailsData loanBasicDetails, boolean isWaiverAllowed,
|
||||
int repaymentAndWaiveCount) {
|
||||
final LoanBasicDetailsData loanBasicDetails,
|
||||
final boolean isWaiverAllowed,
|
||||
final int repaymentAndWaiveCount) {
|
||||
|
||||
boolean pendingApproval = (loanBasicDetails.getStatus().getId().equals(100L));
|
||||
boolean waitingForDisbursal = (loanBasicDetails.getStatus().getId().equals(200L));
|
||||
@@ -307,9 +308,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
LoanTransaction waiveOfInterest = loan.deriveDefaultInterestWaiverTransaction();
|
||||
|
||||
EnumOptionData waiverEnum = LoanEnumerations.transactionType(LoanTransactionType.WAIVED);
|
||||
EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVE_INTEREST);
|
||||
|
||||
return new LoanTransactionNewData(waiverEnum, currencyData, waiveOfInterest.getTransactionDate(), waiveOfInterest.getAmount());
|
||||
return new LoanTransactionNewData(null, transactionType, currencyData, waiveOfInterest.getTransactionDate(), waiveOfInterest.getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanTransactionNewData retrieveNewClosureDetails() {
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF);
|
||||
|
||||
return new LoanTransactionNewData(null, transactionType, null, new LocalDate(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -512,8 +523,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
public String loanScheduleSchema() {
|
||||
|
||||
return " ls.loan_id as loanId, ls.installment as period, ls.duedate as dueDate, "
|
||||
+ " ls.principal_amount as principalDue, ls.principal_completed_derived as principalPaid, "
|
||||
+ " ls.interest_amount as interestDue, ls.interest_completed_derived as interestPaid, ls.interest_waived_derived as interestWaived "
|
||||
+ " 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 "
|
||||
+ " from m_loan l "
|
||||
+ " join m_loan_repayment_schedule ls on ls.loan_id = l.id ";
|
||||
}
|
||||
@@ -526,18 +537,32 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
|
||||
final BigDecimal principalDue = rs.getBigDecimal("principalDue");
|
||||
final BigDecimal principalPaid = rs.getBigDecimal("principalPaid");
|
||||
final BigDecimal principalOutstanding = principalDue.subtract(principalPaid);
|
||||
BigDecimal principalWrittenOff = rs.getBigDecimal("principalWrittenOff");
|
||||
if (principalWrittenOff == null) {
|
||||
principalWrittenOff = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
// 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 BigDecimal interestDue = rs.getBigDecimal("interestDue");
|
||||
final BigDecimal interestPaid = rs.getBigDecimal("interestPaid");
|
||||
BigDecimal interestWaived = rs.getBigDecimal("interestWaived");
|
||||
if (interestWaived == null) {
|
||||
interestWaived = BigDecimal.ZERO;
|
||||
}
|
||||
final BigDecimal interestOutstanding = interestDue.subtract(interestPaid).subtract(interestWaived);
|
||||
BigDecimal interestWrittenOff = rs.getBigDecimal("interestWrittenOff");
|
||||
if (interestWrittenOff == null) {
|
||||
interestWrittenOff = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
// TODO - KW - rather than calculate this here should we put calculation on derived column on table like other columns?
|
||||
final BigDecimal interestOutstanding = interestDue.subtract(interestPaid).subtract(interestWaived).subtract(interestWrittenOff);
|
||||
|
||||
final BigDecimal totalDueForPeriod = principalDue.add(interestDue);
|
||||
final BigDecimal totalPaidForPeriod = principalPaid.add(interestPaid);
|
||||
final BigDecimal totalWaivedForPeriod = interestWaived;
|
||||
final BigDecimal totalWrittenOffForPeriod = principalWrittenOff.add(interestWrittenOff);
|
||||
final BigDecimal totalOutstandingForPeriod = principalOutstanding.add(interestOutstanding);
|
||||
|
||||
final LocalDate fromDate = this.lastDueDate;
|
||||
@@ -548,50 +573,44 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
outstandingLoanBalance = outstandingLoanBalance.subtract(principalDue);
|
||||
|
||||
return LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate, dueDate,
|
||||
principalDue, principalPaid, principalOutstanding, outstandingPrincipleBalanceOfLoan, interestDue,
|
||||
interestPaid, interestWaived, interestOutstanding, totalDueForPeriod, totalPaidForPeriod, totalWaivedForPeriod,
|
||||
principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipleBalanceOfLoan, interestDue,
|
||||
interestPaid, interestWaived, interestWrittenOff, interestOutstanding, totalDueForPeriod, totalPaidForPeriod, totalWaivedForPeriod, totalWrittenOffForPeriod,
|
||||
totalOutstandingForPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LoanPaymentsMapper implements
|
||||
RowMapper<LoanRepaymentTransactionData> {
|
||||
private static final class LoanTransactionsMapper implements RowMapper<LoanTransactionNewData> {
|
||||
|
||||
public String LoanPaymentsSchema() {
|
||||
|
||||
return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as `date`, tr.amount as total, "
|
||||
+ " 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.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, "
|
||||
+ " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode "
|
||||
+ " from m_loan l "
|
||||
+ " join m_loan_transaction tr on tr.loan_id = l.id"
|
||||
+ " join m_currency rc on rc.`code` = l.currency_code ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanRepaymentTransactionData mapRow(final ResultSet rs,
|
||||
public LoanTransactionNewData mapRow(final ResultSet rs,
|
||||
@SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
String currencyCode = rs.getString("currencyCode");
|
||||
String currencyName = rs.getString("currencyName");
|
||||
String currencyNameCode = rs.getString("currencyNameCode");
|
||||
String currencyDisplaySymbol = rs
|
||||
.getString("currencyDisplaySymbol");
|
||||
Integer currencyDigits = JdbcSupport.getInteger(rs,
|
||||
"currencyDigits");
|
||||
String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||
Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
||||
CurrencyData currencyData = new CurrencyData(currencyCode,
|
||||
currencyName, currencyDigits, currencyDisplaySymbol,
|
||||
currencyNameCode);
|
||||
|
||||
Long id = rs.getLong("id");
|
||||
int transactionTypeInt = JdbcSupport.getInteger(rs,
|
||||
"transactionType");
|
||||
EnumOptionData transactionType = LoanEnumerations
|
||||
.transactionType(transactionTypeInt);
|
||||
int transactionTypeInt = JdbcSupport.getInteger(rs, "transactionType");
|
||||
EnumOptionData transactionType = LoanEnumerations.transactionType(transactionTypeInt);
|
||||
LocalDate date = JdbcSupport.getLocalDate(rs, "date");
|
||||
BigDecimal totalBD = rs.getBigDecimal("total");
|
||||
MoneyData total = MoneyData.of(currencyData, totalBD);
|
||||
BigDecimal totalAmount = rs.getBigDecimal("total");
|
||||
|
||||
return new LoanRepaymentTransactionData(id, transactionType, date, total);
|
||||
return new LoanTransactionNewData(id, transactionType, currencyData, date, totalAmount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -36,6 +36,14 @@ public class LoanSchedulePeriodDataWrapper {
|
||||
}
|
||||
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;
|
||||
@@ -68,6 +76,14 @@ public class LoanSchedulePeriodDataWrapper {
|
||||
}
|
||||
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;
|
||||
|
||||
+15
-1
@@ -12,7 +12,7 @@ public class LoanTransactionCommandValidator {
|
||||
|
||||
private final LoanTransactionCommand command;
|
||||
|
||||
public LoanTransactionCommandValidator(LoanTransactionCommand command) {
|
||||
public LoanTransactionCommandValidator(final LoanTransactionCommand command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
@@ -31,4 +31,18 @@ public class LoanTransactionCommandValidator {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateNonMonetaryTransaction() {
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
||||
|
||||
baseDataValidator.reset().parameter("loanId").value(command.getLoanId()).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset().parameter("transactionDate").value(command.getTransactionDate()).notNull();
|
||||
baseDataValidator.reset().parameter("note").value(command.getNote()).notExceedingLengthOf(1000);
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -46,7 +46,13 @@ public interface LoanWritePlatformService {
|
||||
|
||||
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
||||
EntityIdentifier waiveInterestOnLoan(LoanTransactionCommand command);
|
||||
|
||||
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
||||
EntityIdentifier writeOff(LoanTransactionCommand command);
|
||||
|
||||
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
||||
EntityIdentifier closeAsRescheduled(LoanTransactionCommand command);
|
||||
|
||||
@PreAuthorize(value = "hasRole('ORGANISATION_ADMINISTRATION_SUPER_USER_ROLE')")
|
||||
EntityIdentifier addLoanCharge(LoanChargeCommand command);
|
||||
|
||||
|
||||
+62
-4
@@ -8,7 +8,7 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
|
||||
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
|
||||
import org.mifosng.platform.api.commands.LoanApplicationCommand;
|
||||
@@ -161,7 +161,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final LoanTransactionProcessingStrategy strategy = this.loanAssembler.findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId());
|
||||
final Set<LoanCharge> charges = this.loanChargeAssembler.assembleFrom(command.getCharges(), loanProduct.getCharges(), loan.getPrincpal().getAmount());
|
||||
|
||||
final LoanScheduleNewData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(command.toCalculateLoanScheduleCommand());
|
||||
final LoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(command.toCalculateLoanScheduleCommand());
|
||||
loan.modifyLoanApplication(command, client, loanProduct, fund, strategy, loanSchedule, charges, loanOfficer);
|
||||
|
||||
this.loanRepository.save(loan);
|
||||
@@ -373,7 +373,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loanTermFrequency, loanTermFrequencyType,
|
||||
actualDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate, loanChargeCommands);
|
||||
|
||||
LoanScheduleNewData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(calculateCommand);
|
||||
LoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(calculateCommand);
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> modifiedLoanRepaymentSchedule = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
|
||||
@@ -494,7 +494,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// adjustment is only supported for repayments and waivers at present
|
||||
LocalDate transactionDate = command.getTransactionDate();
|
||||
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmount, transactionDate);
|
||||
if (transactionToAdjust.isWaiver()) {
|
||||
if (transactionToAdjust.isInterestWaiver()) {
|
||||
newTransactionDetail = LoanTransaction.waiver(loan, transactionAmount, transactionDate);
|
||||
}
|
||||
|
||||
@@ -540,7 +540,63 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
return new EntityIdentifier(loan.getId());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public EntityIdentifier writeOff(final LoanTransactionCommand command) {
|
||||
context.authenticatedUser();
|
||||
|
||||
final LoanTransactionCommandValidator validator = new LoanTransactionCommandValidator(command);
|
||||
validator.validateNonMonetaryTransaction();
|
||||
|
||||
final Loan loan = this.loanRepository.findOne(command.getLoanId());
|
||||
if (loan == null) {
|
||||
throw new LoanNotFoundException(command.getLoanId());
|
||||
}
|
||||
|
||||
final LoanTransaction writeoff = loan.closeAsWrittenOff(command.getTransactionDate(), defaultLoanLifecycleStateMachine());
|
||||
|
||||
this.loanTransactionRepository.save(writeoff);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.getNote();
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
final Note note = Note.loanTransactionNote(loan, writeoff, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
return new EntityIdentifier(loan.getId());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public EntityIdentifier closeAsRescheduled(final LoanTransactionCommand command) {
|
||||
context.authenticatedUser();
|
||||
|
||||
final LoanTransactionCommandValidator validator = new LoanTransactionCommandValidator(command);
|
||||
validator.validateNonMonetaryTransaction();
|
||||
|
||||
final Loan loan = this.loanRepository.findOne(command.getLoanId());
|
||||
if (loan == null) {
|
||||
throw new LoanNotFoundException(command.getLoanId());
|
||||
}
|
||||
|
||||
// FIXME - kw - HANDLE closed and rescheduled case.
|
||||
final LoanTransaction writeoff = loan.closeAsWrittenOff(command.getTransactionDate(), defaultLoanLifecycleStateMachine());
|
||||
|
||||
this.loanTransactionRepository.save(writeoff);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.getNote();
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
final Note note = Note.loanTransactionNote(loan, writeoff, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
return new EntityIdentifier(loan.getId());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public EntityIdentifier addLoanCharge(LoanChargeCommand command) {
|
||||
this.context.authenticatedUser();
|
||||
@@ -579,6 +635,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
return new EntityIdentifier(loanCharge.getId());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public EntityIdentifier updateLoanCharge(final LoanChargeCommand command) {
|
||||
|
||||
@@ -604,6 +661,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
throw new ChargeNotFoundException(command.getId());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public EntityIdentifier deleteLoanCharge(Long loanId, Long loanChargeId) {
|
||||
|
||||
|
||||
+31
-12
@@ -173,20 +173,32 @@ public class LoanEnumerations {
|
||||
public static EnumOptionData transactionType(final LoanTransactionType type) {
|
||||
EnumOptionData optionData = null;
|
||||
switch (type) {
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(LoanTransactionType.INVALID.getValue().longValue(), LoanTransactionType.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
case DISBURSEMENT:
|
||||
optionData= new EnumOptionData(LoanTransactionType.DISBURSEMENT.getValue().longValue(), LoanTransactionType.DISBURSEMENT.getCode(), "Dibursement");
|
||||
break;
|
||||
case REPAYMENT:
|
||||
optionData = new EnumOptionData(LoanTransactionType.REPAYMENT.getValue().longValue(), LoanTransactionType.REPAYMENT.getCode(), "Repayment");
|
||||
break;
|
||||
case REVERSAL:
|
||||
optionData = new EnumOptionData(LoanTransactionType.REVERSAL.getValue().longValue(), LoanTransactionType.REVERSAL.getCode(), "Reversal");
|
||||
case REPAYMENT_AT_DISBURSEMENT:
|
||||
optionData = new EnumOptionData(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue().longValue(), LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getCode(), "Repayment (at time of disbursement)");
|
||||
break;
|
||||
case WAIVED:
|
||||
optionData = new EnumOptionData(LoanTransactionType.WAIVED.getValue().longValue(), LoanTransactionType.WAIVED.getCode(), "Waiver");
|
||||
case CONTRA:
|
||||
optionData = new EnumOptionData(LoanTransactionType.CONTRA.getValue().longValue(), LoanTransactionType.CONTRA.getCode(), "Reversal");
|
||||
break;
|
||||
default:
|
||||
optionData = new EnumOptionData(LoanTransactionType.INVALID.getValue().longValue(), LoanTransactionType.INVALID.getCode(), "Invalid");
|
||||
case WAIVE_INTEREST:
|
||||
optionData = new EnumOptionData(LoanTransactionType.WAIVE_INTEREST.getValue().longValue(), LoanTransactionType.WAIVE_INTEREST.getCode(), "Waive interest");
|
||||
break;
|
||||
case MARKED_FOR_RESCHEDULING:
|
||||
optionData = new EnumOptionData(LoanTransactionType.MARKED_FOR_RESCHEDULING.getValue().longValue(), LoanTransactionType.MARKED_FOR_RESCHEDULING.getCode(), "Close (as rescheduled)");
|
||||
break;
|
||||
case WRITEOFF:
|
||||
optionData = new EnumOptionData(LoanTransactionType.WRITEOFF.getValue().longValue(), LoanTransactionType.WRITEOFF.getCode(), "Close (as written-off)");
|
||||
break;
|
||||
case RECOVERY_REPAYMENT:
|
||||
optionData = new EnumOptionData(LoanTransactionType.RECOVERY_REPAYMENT.getValue().longValue(), LoanTransactionType.RECOVERY_REPAYMENT.getCode(), "Repayment (after write-off)");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
@@ -197,8 +209,11 @@ public class LoanEnumerations {
|
||||
}
|
||||
|
||||
public static EnumOptionData status(final LoanStatus status) {
|
||||
EnumOptionData optionData = null;
|
||||
EnumOptionData optionData = new EnumOptionData(LoanStatus.INVALID.getValue().longValue(), LoanStatus.INVALID.getCode(), "Invalid");
|
||||
switch (status) {
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(LoanStatus.INVALID.getValue().longValue(), LoanStatus.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
case SUBMITED_AND_PENDING_APPROVAL:
|
||||
optionData = new EnumOptionData(LoanStatus.SUBMITED_AND_PENDING_APPROVAL.getValue().longValue(), LoanStatus.SUBMITED_AND_PENDING_APPROVAL.getCode(), "Submitted and pending approval");
|
||||
break;
|
||||
@@ -214,16 +229,20 @@ public class LoanEnumerations {
|
||||
case WITHDRAWN_BY_CLIENT:
|
||||
optionData = new EnumOptionData(LoanStatus.WITHDRAWN_BY_CLIENT.getValue().longValue(), LoanStatus.WITHDRAWN_BY_CLIENT.getCode(), "Withdrawn by applicant");
|
||||
break;
|
||||
case CLOSED:
|
||||
optionData = new EnumOptionData(LoanStatus.CLOSED.getValue().longValue(), LoanStatus.CLOSED.getCode(), "Closed");
|
||||
case CLOSED_OBLIGATIONS_MET:
|
||||
optionData = new EnumOptionData(LoanStatus.CLOSED_OBLIGATIONS_MET.getValue().longValue(), LoanStatus.CLOSED_OBLIGATIONS_MET.getCode(), "Closed (obligations met)");
|
||||
break;
|
||||
case CLOSED_WRITTEN_OFF:
|
||||
optionData = new EnumOptionData(LoanStatus.CLOSED_WRITTEN_OFF.getValue().longValue(), LoanStatus.CLOSED_WRITTEN_OFF.getCode(), "Closed (written off)");
|
||||
break;
|
||||
case CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT:
|
||||
optionData = new EnumOptionData(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT.getValue().longValue(), LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT.getCode(), "Closed (rescheduled)");
|
||||
break;
|
||||
case OVERPAID:
|
||||
optionData = new EnumOptionData(LoanStatus.OVERPAID.getValue().longValue(), LoanStatus.OVERPAID.getCode(), "Overpaid");
|
||||
break;
|
||||
default:
|
||||
optionData = new EnumOptionData(LoanStatus.INVALID.getValue().longValue(), LoanStatus.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
}
|
||||
|
||||
return optionData;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,14 +5,14 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
import org.mifosng.platform.loan.domain.LoanCharge;
|
||||
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
|
||||
|
||||
public interface AmortizationLoanScheduleGenerator {
|
||||
|
||||
LoanScheduleNewData generate(
|
||||
LoanScheduleData generate(
|
||||
ApplicationCurrency applicationCurrency,
|
||||
LoanProductRelatedDetail loanScheduleInfo,
|
||||
LocalDate disbursementDate,
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
import org.mifosng.platform.loan.domain.AmortizationMethod;
|
||||
import org.mifosng.platform.loan.domain.LoanCharge;
|
||||
@@ -36,7 +36,7 @@ public class DecliningBalanceMethodLoanScheduleGenerator implements LoanSchedule
|
||||
private final AmortizationLoanScheduleGeneratorFactory amortizationLoanScheduleGeneratorFactory = new AmortizationLoanScheduleGeneratorFactory();
|
||||
|
||||
@Override
|
||||
public LoanScheduleNewData generate(
|
||||
public LoanScheduleData generate(
|
||||
final ApplicationCurrency applicationCurrency,
|
||||
final LoanProductRelatedDetail loanScheduleInfo,
|
||||
final Integer loanTermFrequency,
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ import java.util.Set;
|
||||
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
@@ -27,7 +27,7 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
|
||||
private final PmtCalculator pmtCalculator = new PmtCalculator();
|
||||
|
||||
@Override
|
||||
public LoanScheduleNewData generate(
|
||||
public LoanScheduleData generate(
|
||||
final ApplicationCurrency currency,
|
||||
final LoanProductRelatedDetail loanScheduleInfo,
|
||||
final LocalDate disbursementDate,
|
||||
@@ -150,7 +150,7 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
|
||||
currency.getDisplaySymbol(),
|
||||
currency.getNameCode());
|
||||
|
||||
return new LoanScheduleNewData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -8,7 +8,7 @@ import java.util.Set;
|
||||
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
@@ -23,7 +23,7 @@ public class EqualPrincipalAmortizationLoanScheduleGenerator implements Amortiza
|
||||
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
|
||||
|
||||
@Override
|
||||
public LoanScheduleNewData generate(
|
||||
public LoanScheduleData generate(
|
||||
final ApplicationCurrency currency,
|
||||
final LoanProductRelatedDetail loanScheduleInfo,
|
||||
final LocalDate disbursementDate,
|
||||
@@ -131,7 +131,7 @@ public class EqualPrincipalAmortizationLoanScheduleGenerator implements Amortiza
|
||||
currency.getDisplaySymbol(),
|
||||
currency.getNameCode());
|
||||
|
||||
return new LoanScheduleNewData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -10,7 +10,7 @@ import java.util.Set;
|
||||
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
@@ -26,7 +26,7 @@ public class FlatMethodLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
|
||||
|
||||
@Override
|
||||
public LoanScheduleNewData generate(
|
||||
public LoanScheduleData generate(
|
||||
final ApplicationCurrency currency,
|
||||
final LoanProductRelatedDetail loanScheduleInfo,
|
||||
final Integer loanTermFrequency,
|
||||
@@ -138,7 +138,7 @@ public class FlatMethodLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||
currency.getDisplaySymbol(),
|
||||
currency.getNameCode());
|
||||
|
||||
return new LoanScheduleNewData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
|
||||
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -3,7 +3,7 @@ package org.mifosng.platform.loanschedule.domain;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.LoanScheduleNewData;
|
||||
import org.mifosng.platform.api.LoanScheduleData;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
import org.mifosng.platform.loan.domain.LoanCharge;
|
||||
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
|
||||
@@ -11,7 +11,7 @@ import org.mifosng.platform.loan.domain.PeriodFrequencyType;
|
||||
|
||||
public interface LoanScheduleGenerator {
|
||||
|
||||
LoanScheduleNewData generate(ApplicationCurrency applicationCurrency,
|
||||
LoanScheduleData generate(ApplicationCurrency applicationCurrency,
|
||||
LoanProductRelatedDetail loanScheduleInfo,
|
||||
Integer loanTermFrequency,
|
||||
PeriodFrequencyType loanTermFrequencyType,
|
||||
|
||||
Reference in New Issue
Block a user