mifosx-58: wip on data to reprsesent loan schedule.

This commit is contained in:
Keith Woodlock
2012-09-18 15:15:37 +01:00
parent 3e5b47f562
commit c6317acfae
8 changed files with 231 additions and 61 deletions
@@ -160,7 +160,7 @@ public class LoansApiResource {
repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers);
return this.apiJsonSerializerService.serialzieLoanAccountDataToJson(prettyPrint, responseParameters, newLoanAccount);
return this.apiJsonSerializerService.serializeLoanAccountDataToJson(prettyPrint, responseParameters, newLoanAccount);
}
@GET
@@ -258,14 +258,15 @@ public class LoansApiResource {
repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers);
return this.apiJsonSerializerService.serialzieLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount);
return this.apiJsonSerializerService.serializeLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response calculateLoanScheduleOrSubmitLoanApplication(
public String calculateLoanScheduleOrSubmitLoanApplication(
@QueryParam("command") final String commandParam,
@Context final UriInfo uriInfo,
final String jsonRequestBody) {
LoanApplicationCommand command = this.apiDataConversionService.convertJsonToLoanApplicationCommand(null, jsonRequestBody);
@@ -273,12 +274,22 @@ public class LoansApiResource {
if (is(commandParam, "calculateLoanSchedule")) {
CalculateLoanScheduleCommand calculateLoanScheduleCommand = command.toCalculateLoanScheduleCommand();
NewLoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanScheduleNew(calculateLoanScheduleCommand);
return Response.ok().entity(loanSchedule).build();
final Set<String> typicalLoanScheduleResponseParameters = new HashSet<String>(
Arrays.asList("periods", "cumulativePrincipalDisbursed"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalLoanScheduleResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return this.apiJsonSerializerService.serializeLoanScheduleDataToJson(prettyPrint, responseParameters, loanSchedule);
}
EntityIdentifier identifier = this.loanWritePlatformService.submitLoanApplication(command);
final EntityIdentifier identifier = this.loanWritePlatformService.submitLoanApplication(command);
return Response.ok().entity(identifier).build();
return this.apiJsonSerializerService.serializeEntityIdentifier(identifier);
}
@PUT
@@ -1,6 +1,9 @@
package org.mifosng.platform.api;
import java.math.BigDecimal;
import java.util.Collection;
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
/**
* Immutable data object to represent aspects of a loan schedule such as:
@@ -10,29 +13,30 @@ import java.math.BigDecimal;
* <li>repayment schedule - the principal due, outstanding balance and cost of loan items such as interest and charges</li>
* </ul>
*/
@SuppressWarnings("unused")
public class NewLoanScheduleData {
/**
* The cumulative total of all money (principal) disbursed to the loan applicant.
*/
private final BigDecimal principalDisbursed;
private final BigDecimal principalPaid;
private final BigDecimal principalOutstanding;
private final BigDecimal cumulativePrincipalDisbursed;
private final BigDecimal cumulativePrincipalPaid;
private final BigDecimal cumulativePrincipalOutstanding;
/**
* The total interest expected on any principal disbursed.
*/
private final BigDecimal interestExpected;
private final BigDecimal interestPaid;
private final BigDecimal interestWaived;
private final BigDecimal interestOutstanding;
private final BigDecimal cumulativeInterestExpected;
private final BigDecimal cumulativeInterestPaid;
private final BigDecimal cumulativeInterestWaived;
private final BigDecimal cumulativeInterestOutstanding;
/**
* The cumulative total of all charges applied on the loan to date.
*/
private final BigDecimal chargesToDate;
private final BigDecimal chargesPaid;
private final BigDecimal chargesOutstanding;
private final BigDecimal cumulativeChargesToDate;
private final BigDecimal cumulativeChargesPaid;
private final BigDecimal cumulativeChargesOutstanding;
/**
* The cumulative total of all costs on the loan.
@@ -49,20 +53,49 @@ public class NewLoanScheduleData {
*/
private final BigDecimal totalExpectedRepayment;
private final BigDecimal totalInArrears;
/**
* <code>periods</code>
*/
private final Collection<LoanSchedulePeriodData> periods;
public NewLoanScheduleData() {
this.principalDisbursed = null;
this.principalPaid = null;
this.principalOutstanding = null;
this.cumulativePrincipalDisbursed = null;
this.cumulativePrincipalPaid = null;
this.cumulativePrincipalOutstanding = null;
this.interestExpected = null;
this.interestPaid = null;
this.interestWaived = null;
this.interestOutstanding = null;
this.cumulativeInterestExpected = null;
this.cumulativeInterestPaid = null;
this.cumulativeInterestWaived = null;
this.cumulativeInterestOutstanding = null;
this.chargesToDate = null;
this.chargesPaid = null;
this.chargesOutstanding = null;
this.cumulativeChargesToDate = null;
this.cumulativeChargesPaid = null;
this.cumulativeChargesOutstanding = null;
this.totalCostOfLoan = null;
this.totalExpectedRepayment = null;
this.totalInArrears = null;
this.periods = null;
}
public NewLoanScheduleData(final Collection<LoanSchedulePeriodData> periods) {
this.periods = periods;
this.cumulativePrincipalDisbursed = null;
this.cumulativePrincipalPaid = null;
this.cumulativePrincipalOutstanding = null;
this.cumulativeInterestExpected = null;
this.cumulativeInterestPaid = null;
this.cumulativeInterestWaived = null;
this.cumulativeInterestOutstanding = null;
this.cumulativeChargesToDate = null;
this.cumulativeChargesPaid = null;
this.cumulativeChargesOutstanding = null;
this.totalCostOfLoan = null;
@@ -1,8 +1,114 @@
package org.mifosng.platform.api.data;
import java.math.BigDecimal;
import org.joda.time.Days;
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;
private final LocalDate fromDate;
private final LocalDate dueDate;
private final Integer daysInPeriod;
private final BigDecimal principalDisbursed;
private final BigDecimal principalOriginalDue;
private final BigDecimal principalDue;
private final BigDecimal principalPaid;
private final BigDecimal principalOutstanding;
private final BigDecimal principalTotalBalanceOutstanding;
private final BigDecimal interestOriginalDue;
private final BigDecimal interestDue;
private final BigDecimal interestPaid;
private final BigDecimal interestOutstanding;
private final BigDecimal chargesDue;
private final BigDecimal chargesPaid;
private final BigDecimal chargesOutstanding;
private final BigDecimal totalDueForPeriod;
public static LoanSchedulePeriodData disbursement(final LocalDate disbursementDate, final BigDecimal principalDisbursed) {
Integer periodNumber = Integer.valueOf(0);
LocalDate from = null;
return new LoanSchedulePeriodData(periodNumber, from, disbursementDate, principalDisbursed);
}
public static LoanSchedulePeriodData repaymentPeriod(final Integer periodNumber,
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);
}
private LoanSchedulePeriodData(
final Integer periodNumber,
final LocalDate fromDate,
final LocalDate dueDate,
final BigDecimal principalDisbursed) {
this.period = periodNumber;
this.fromDate = fromDate;
this.dueDate = dueDate;
if (fromDate != null) {
this.daysInPeriod = Days.daysBetween(fromDate, dueDate).getDays();
} else {
this.daysInPeriod = null;
}
this.principalDisbursed = principalDisbursed;
this.principalOriginalDue = null;
this.principalDue = null;
this.principalPaid = null;
this.principalOutstanding = null;
this.principalTotalBalanceOutstanding = principalDisbursed;
this.interestOriginalDue = null;
this.interestDue = null;
this.interestPaid = null;
this.interestOutstanding = null;
this.chargesDue = null;
this.chargesPaid = null;
this.chargesOutstanding = null;
this.totalDueForPeriod = null;
}
private LoanSchedulePeriodData(
final Integer periodNumber,
final LocalDate fromDate,
final LocalDate dueDate,
final BigDecimal principalOriginalDue, final BigDecimal principalOutstanding, final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal totalDueForPeriod) {
this.period = periodNumber;
this.fromDate = fromDate;
this.dueDate = dueDate;
if (fromDate != null) {
this.daysInPeriod = Days.daysBetween(fromDate, dueDate).getDays();
} else {
this.daysInPeriod = null;
}
this.principalDisbursed = null;
this.principalOriginalDue = principalOriginalDue;
this.principalDue = principalOriginalDue;
this.principalPaid = null;
this.principalOutstanding = principalOriginalDue;
this.principalTotalBalanceOutstanding = principalOutstanding;
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
this.interestDue = interestDueOnPrincipalOutstanding;
this.interestPaid = null;
this.interestOutstanding = interestDueOnPrincipalOutstanding;
this.chargesDue = null;
this.chargesPaid = null;
this.chargesOutstanding = null;
this.totalDueForPeriod = totalDueForPeriod;
}
}
@@ -439,8 +439,8 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
throw new InvalidJsonException();
}
Type typeOfMap = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap);
Type typeOfMap = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> requestMap = gsonConverter.fromJson(json, typeOfMap);
Set<String> supportedParams = new HashSet<String>(
Arrays.asList("clientId", "productId", "externalId", "fundId", "transactionProcessingStrategyId",
@@ -3,6 +3,7 @@ package org.mifosng.platform.api.infrastructure;
import java.util.Collection;
import java.util.Set;
import org.mifosng.platform.api.NewLoanScheduleData;
import org.mifosng.platform.api.data.AdditionalFieldsSetData;
import org.mifosng.platform.api.data.AppUserData;
import org.mifosng.platform.api.data.AuthenticatedUserData;
@@ -13,6 +14,7 @@ import org.mifosng.platform.api.data.ConfigurationData;
import org.mifosng.platform.api.data.DatatableData;
import org.mifosng.platform.api.data.DepositAccountData;
import org.mifosng.platform.api.data.DepositProductData;
import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.FundData;
import org.mifosng.platform.api.data.GenericResultsetData;
import org.mifosng.platform.api.data.GroupData;
@@ -90,8 +92,10 @@ public interface ApiJsonSerializerService {
String serializeNoteDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<NoteData> notes);
String serializeNoteDataToJson(boolean prettyPrint, Set<String> responseParameters, NoteData note);
String serializeLoanScheduleDataToJson(boolean prettyPrint, Set<String> responseParameters, NewLoanScheduleData loanSchedule);
String serialzieLoanAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanAccountData loanAccount);
String serializeLoanAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanAccountData loanAccount);
String serializeLoanTransactionDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanTransactionData transaction);
@@ -102,4 +106,6 @@ public interface ApiJsonSerializerService {
String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, StaffData staff);
String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<StaffData> staff);
String serializeEntityIdentifier(EntityIdentifier identifier);
}
@@ -5,6 +5,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.mifosng.platform.api.NewLoanScheduleData;
import org.mifosng.platform.api.data.AdditionalFieldsSetData;
import org.mifosng.platform.api.data.AppUserData;
import org.mifosng.platform.api.data.AuthenticatedUserData;
@@ -15,6 +16,7 @@ import org.mifosng.platform.api.data.ConfigurationData;
import org.mifosng.platform.api.data.DatatableData;
import org.mifosng.platform.api.data.DepositAccountData;
import org.mifosng.platform.api.data.DepositProductData;
import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.FundData;
import org.mifosng.platform.api.data.GenericResultsetData;
import org.mifosng.platform.api.data.GroupData;
@@ -133,6 +135,9 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
"createdOn", "updatedById", "updatedByUsername",
"updatedOn"));
private static final Set<String> LOAN_SCHEDULE_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("periods", "cumulativePrincipalDisbursed"));
private static final Set<String> LOAN_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "externalId", "clientId", "clientName", "fundId", "fundName",
"loanProductId", "loanProductName", "loanProductDescription",
@@ -494,7 +499,14 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
}
@Override
public String serialzieLoanAccountDataToJson(final boolean prettyPrint,
public String serializeLoanScheduleDataToJson(final boolean prettyPrint, final Set<String> responseParameters, final NewLoanScheduleData loanSchedule) {
final Gson gsonDeserializer = helper
.createGsonBuilderWithParameterExclusionSerializationStrategy(LOAN_SCHEDULE_DATA_PARAMETERS, prettyPrint, responseParameters);
return helper.serializedJsonFrom(gsonDeserializer, loanSchedule);
}
@Override
public String serializeLoanAccountDataToJson(final boolean prettyPrint,
final Set<String> responseParameters,
final LoanAccountData loanAccount) {
final Gson gsonDeserializer = helper
@@ -555,4 +567,10 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
staff.toArray(new StaffData[staff.size()]));
}
@Override
public String serializeEntityIdentifier(final EntityIdentifier identifier) {
final Set<String> DATA_PARAMETERS = new HashSet<String>(Arrays.asList("entityId"));
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(DATA_PARAMETERS, false, DATA_PARAMETERS);
return helper.serializedJsonFrom(gsonDeserializer, identifier);
}
}
@@ -70,20 +70,20 @@ public class CalculationPlatformServiceImpl implements CalculationPlatformServic
LoanProductRelatedDetail loanScheduleRelatedDetails = this.loanProductRelatedDetailAssembler.assembleFrom(command);
final Integer loanTermFrequency = command.getLoanTermFrequency();
final PeriodFrequencyType loanTermFrequencyType = PeriodFrequencyType.fromInt(command.getLoanTermFrequencyType());
// final Integer loanTermFrequency = command.getLoanTermFrequency();
// final PeriodFrequencyType loanTermFrequencyType = PeriodFrequencyType.fromInt(command.getLoanTermFrequencyType());
final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestType());
LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod);
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(loanScheduleRelatedDetails.getCurrency().getCode());
// ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(loanScheduleRelatedDetails.getCurrency().getCode());
CurrencyData currencyData = new CurrencyData(
applicationCurrency.getCode(),
applicationCurrency.getName(),
loanScheduleRelatedDetails.getCurrency().getDigitsAfterDecimal(),
applicationCurrency.getDisplaySymbol(),
applicationCurrency.getNameCode());
// CurrencyData currencyData = new CurrencyData(
// applicationCurrency.getCode(),
// applicationCurrency.getName(),
// loanScheduleRelatedDetails.getCurrency().getDigitsAfterDecimal(),
// applicationCurrency.getDisplaySymbol(),
// applicationCurrency.getNameCode());
return loanScheduleGenerator.generate(loanScheduleRelatedDetails,
command.getExpectedDisbursementDate(),
@@ -2,6 +2,7 @@ package org.mifosng.platform.loanschedule.domain;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.joda.time.Days;
@@ -38,7 +39,7 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
// 1. add disbursements to loan schedule
// 2.
List<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>();
Collection<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>();
// determine 'total payment' for each repayment based on pmt function (and hence the total due overall)
final MonetaryCurrency monetaryCurrency = loanScheduleInfo.getPrincipal().getCurrency();
@@ -57,12 +58,17 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
scheduledDates,
idealDisbursementDateBasedOnFirstRepaymentDate);
// create entries of disbursement period on loan schedule
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursement(disbursementDate, loanScheduleInfo.getPrincipal().getAmount());
periods.add(disbursementPeriod);
LocalDate startDate = disbursementDate;
int installmentNumber = 1;
int periodNumber = 1;
for (LocalDate scheduledDueDate : scheduledDates) {
// number of days from startDate to this scheduledDate
int daysInPeriod = Days.daysBetween(startDate.toDateMidnight().toDateTime(), scheduledDueDate.toDateMidnight().toDateTime()).getDays();
int daysInPeriod = Days.daysBetween(startDate, scheduledDueDate).getDays();
Money interestForInstallment = this.periodicInterestRateCalculator.calculateInterestOn(outstandingBalance, periodInterestRateForRepaymentPeriod, daysInPeriod, loanScheduleInfo);
Money principalForInstallment = this.periodicInterestRateCalculator.calculatePrincipalOn(totalDuePerInstallment, interestForInstallment, loanScheduleInfo);
@@ -82,7 +88,7 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
totalPrincipal = totalPrincipal.plus(principalForInstallment);
totalInterest = totalInterest.plus(interestForInstallment);
if (installmentNumber == loanScheduleInfo.getNumberOfRepayments()) {
if (periodNumber == loanScheduleInfo.getNumberOfRepayments()) {
Money principalDifference = totalPrincipal.minus(loanScheduleInfo.getPrincipal());
if (principalDifference.isLessThanZero()) {
principalForInstallment = principalForInstallment.plus(principalDifference.abs());
@@ -102,30 +108,20 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort
outstandingBalance = outstandingBalance.minus(principalForInstallment);
// MoneyData principalPerInstallmentValue = MoneyData.of(currencyData, principalForInstallment.getAmount());
// MoneyData interestPerInstallmentValue = MoneyData.of(currencyData, interestForInstallment.getAmount());
// MoneyData totalInstallmentDueValue = MoneyData.of(currencyData, totalInstallmentDue.getAmount());
// MoneyData outstandingBalanceValue = MoneyData.of(currencyData, outstandingBalance.getAmount());
// ScheduledLoanInstallment installment = new ScheduledLoanInstallment(
// Integer.valueOf(installmentNumber), startDate,
// scheduledDueDate, principalPerInstallmentValue,
// interestPerInstallmentValue,
// totalInstallmentDueValue,
// outstandingBalanceValue);
LoanSchedulePeriodData installment = new LoanSchedulePeriodData();
LoanSchedulePeriodData installment = LoanSchedulePeriodData.repaymentPeriod(periodNumber, startDate,
scheduledDueDate,
principalForInstallment.getAmount(),
outstandingBalance.getAmount(),
interestForInstallment.getAmount(), totalInstallmentDue.getAmount());
periods.add(installment);
startDate = scheduledDueDate;
installmentNumber++;
periodNumber++;
}
return null;
return new NewLoanScheduleData(periods);
}
@Override