squash changes in interest-calculation-extension branch

This commit is contained in:
Keith Woodlock
2012-05-01 17:31:32 +01:00
parent ff120f925c
commit d3d40cabe0
37 changed files with 1639 additions and 406 deletions
@@ -22,6 +22,8 @@ public class LoanProductData implements Serializable {
private int interestRatePeriod; private int interestRatePeriod;
private BigDecimal annualInterestRate = BigDecimal.ZERO; private BigDecimal annualInterestRate = BigDecimal.ZERO;
private int interestMethod; private int interestMethod;
private int interestRateCalculatedInPeriod;
private Integer numberOfInterestFreePeriods = Integer.valueOf(0); private Integer numberOfInterestFreePeriods = Integer.valueOf(0);
private Integer repaidEvery; private Integer repaidEvery;
private int repaymentPeriodFrequency; private int repaymentPeriodFrequency;
@@ -34,6 +36,7 @@ public class LoanProductData implements Serializable {
private List<CurrencyData> possibleCurrencies = new ArrayList<CurrencyData>(); private List<CurrencyData> possibleCurrencies = new ArrayList<CurrencyData>();
private List<EnumOptionReadModel> possibleAmortizationOptions = new ArrayList<EnumOptionReadModel>(); private List<EnumOptionReadModel> possibleAmortizationOptions = new ArrayList<EnumOptionReadModel>();
private List<EnumOptionReadModel> possibleInterestOptions = new ArrayList<EnumOptionReadModel>(); private List<EnumOptionReadModel> possibleInterestOptions = new ArrayList<EnumOptionReadModel>();
private List<EnumOptionReadModel> possibleInterestRateCalculatedInPeriodOptions = new ArrayList<EnumOptionReadModel>();
private List<EnumOptionReadModel> repaymentFrequencyOptions = new ArrayList<EnumOptionReadModel>(); private List<EnumOptionReadModel> repaymentFrequencyOptions = new ArrayList<EnumOptionReadModel>();
private List<EnumOptionReadModel> interestFrequencyOptions = new ArrayList<EnumOptionReadModel>(); private List<EnumOptionReadModel> interestFrequencyOptions = new ArrayList<EnumOptionReadModel>();
@@ -47,7 +50,8 @@ public class LoanProductData implements Serializable {
final MoneyData principalMoney, final MoneyData principalMoney,
final BigDecimal interestRatePerPeriod, final BigDecimal interestRatePerPeriod,
final int interestRatePeriod, final BigDecimal annualInterestRate, final int interestRatePeriod, final BigDecimal annualInterestRate,
final int interestMethod, final Integer repaidEvery, final int interestMethod, final int interestCalculationInPeriodMethod,
final Integer repaidEvery,
final int repaymentPeriodFrequency, final Integer numberOfRepayments, final int repaymentPeriodFrequency, final Integer numberOfRepayments,
final int amortizationMethod, MoneyData inArrearsTolerance, DateTime createdOn, DateTime lastModifedOn) { final int amortizationMethod, MoneyData inArrearsTolerance, DateTime createdOn, DateTime lastModifedOn) {
this.id = id; this.id = id;
@@ -60,6 +64,7 @@ public class LoanProductData implements Serializable {
this.interestRatePeriod = interestRatePeriod; this.interestRatePeriod = interestRatePeriod;
this.annualInterestRate = annualInterestRate; this.annualInterestRate = annualInterestRate;
this.interestMethod = interestMethod; this.interestMethod = interestMethod;
this.interestRateCalculatedInPeriod = interestCalculationInPeriodMethod;
this.numberOfRepayments = numberOfRepayments; this.numberOfRepayments = numberOfRepayments;
this.repaidEvery = repaidEvery; this.repaidEvery = repaidEvery;
this.repaymentPeriodFrequency = repaymentPeriodFrequency; this.repaymentPeriodFrequency = repaymentPeriodFrequency;
@@ -256,4 +261,21 @@ public class LoanProductData implements Serializable {
public void setNumberOfInterestFreePeriods(Integer numberOfInterestFreePeriods) { public void setNumberOfInterestFreePeriods(Integer numberOfInterestFreePeriods) {
this.numberOfInterestFreePeriods = numberOfInterestFreePeriods; this.numberOfInterestFreePeriods = numberOfInterestFreePeriods;
} }
public int getInterestRateCalculatedInPeriod() {
return interestRateCalculatedInPeriod;
}
public void setInterestRateCalculatedInPeriod(int interestRateCalculatedInPeriod) {
this.interestRateCalculatedInPeriod = interestRateCalculatedInPeriod;
}
public List<EnumOptionReadModel> getPossibleInterestRateCalculatedInPeriodOptions() {
return possibleInterestRateCalculatedInPeriodOptions;
}
public void setPossibleInterestRateCalculatedInPeriodOptions(
List<EnumOptionReadModel> possibleInterestRateCalculatedInPeriodOptions) {
this.possibleInterestRateCalculatedInPeriodOptions = possibleInterestRateCalculatedInPeriodOptions;
}
} }
@@ -21,14 +21,15 @@ public class CalculateLoanScheduleCommand {
public CalculateLoanScheduleCommand(final String currencyCode, public CalculateLoanScheduleCommand(final String currencyCode,
final Integer digitsAfterDecimal, final Number principal, final Integer digitsAfterDecimal, final Number principal,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod,
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod,
final boolean flexibleRepaymentSchedule, final boolean flexibleRepaymentSchedule,
final boolean interestRebateAllowed, final boolean interestRebateAllowed,
final LocalDate expectedDisbursementDate, final LocalDate expectedDisbursementDate,
final LocalDate repaymentsStartingFromDate, final LocalDate interestCalculatedFromDate) { final LocalDate repaymentsStartingFromDate, final LocalDate interestCalculatedFromDate) {
commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod,
interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, Integer.valueOf(0), repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, Integer.valueOf(0),
flexibleRepaymentSchedule, interestRebateAllowed); flexibleRepaymentSchedule, interestRebateAllowed);
@@ -173,4 +174,12 @@ public class CalculateLoanScheduleCommand {
public void setInterestCalculatedFromDate(LocalDate interestCalculatedFromDate) { public void setInterestCalculatedFromDate(LocalDate interestCalculatedFromDate) {
this.interestCalculatedFromDate = interestCalculatedFromDate; this.interestCalculatedFromDate = interestCalculatedFromDate;
} }
public Integer getInterestCalculationPeriodMethod() {
return this.commonLoanProperties.getInterestCalculationPeriodMethod();
}
public void setInterestCalculationPeriodMethod(final Integer interestCalculationPeriodMethod) {
this.commonLoanProperties.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
}
} }
@@ -21,6 +21,7 @@ public class CommonLoanProperties {
private BigDecimal interestRatePerPeriod; private BigDecimal interestRatePerPeriod;
private Integer interestRateFrequencyMethod; private Integer interestRateFrequencyMethod;
private Integer interestMethod; private Integer interestMethod;
private Integer interestCalculationPeriodMethod;
private boolean flexibleRepaymentSchedule = false; private boolean flexibleRepaymentSchedule = false;
private boolean interestRebateAllowed = false; private boolean interestRebateAllowed = false;
@@ -31,7 +32,8 @@ public class CommonLoanProperties {
public CommonLoanProperties(final String currencyCode, public CommonLoanProperties(final String currencyCode,
final Integer digitsAfterDecimal, final Number principal, final Integer digitsAfterDecimal, final Number principal,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Number interestRatePerPeriod, Integer interestRateFrequencyMethod,
final Integer interestMethod, final Integer interestCalculationPeriodMethod,
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount, final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount,
final boolean flexibleRepaymentSchedule, final boolean flexibleRepaymentSchedule,
final boolean interestRebateAllowed) { final boolean interestRebateAllowed) {
@@ -46,6 +48,7 @@ public class CommonLoanProperties {
} }
this.interestRateFrequencyMethod = interestRateFrequencyMethod; this.interestRateFrequencyMethod = interestRateFrequencyMethod;
this.interestMethod = interestMethod; this.interestMethod = interestMethod;
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
this.repaymentEvery = repaymentEvery; this.repaymentEvery = repaymentEvery;
this.repaymentFrequency = repaymentFrequency; this.repaymentFrequency = repaymentFrequency;
@@ -169,4 +172,13 @@ public class CommonLoanProperties {
public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) { public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) {
this.inArrearsToleranceAmount = inArrearsToleranceAmount; this.inArrearsToleranceAmount = inArrearsToleranceAmount;
} }
public Integer getInterestCalculationPeriodMethod() {
return interestCalculationPeriodMethod;
}
public void setInterestCalculationPeriodMethod(
Integer interestCalculationPeriodMethod) {
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
}
} }
@@ -19,14 +19,16 @@ public class CreateLoanProductCommand implements LoanProductCommandData {
public CreateLoanProductCommand(final String currencyCode, public CreateLoanProductCommand(final String currencyCode,
final Integer digitsAfterDecimal, final Number principal, final Integer digitsAfterDecimal, final Number principal,
final String name, final String description, final String name, final String description,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Number interestRatePerPeriod, Integer interestRateFrequencyMethod,
final Integer interestMethod, final Integer interestCalculationPeriodMethod,
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount, final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount,
final boolean flexibleRepaymentSchedule, final boolean flexibleRepaymentSchedule,
final boolean interestRebateAllowed) { final boolean interestRebateAllowed) {
this.name = name; this.name = name;
this.description = description; this.description = description;
commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod,
interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed); repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
} }
@@ -238,4 +240,13 @@ public class CreateLoanProductCommand implements LoanProductCommandData {
public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) { public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) {
this.commonLoanProperties.setInArrearsToleranceAmount(inArrearsToleranceAmount); this.commonLoanProperties.setInArrearsToleranceAmount(inArrearsToleranceAmount);
} }
@Override
public Integer getInterestCalculationPeriodMethod() {
return this.commonLoanProperties.getInterestCalculationPeriodMethod();
}
public void setInterestCalculationPeriodMethod(final Integer interestCalculationPeriodMethod) {
this.commonLoanProperties.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
}
} }
@@ -4,40 +4,41 @@ import java.math.BigDecimal;
public interface LoanProductCommandData { public interface LoanProductCommandData {
public abstract String getName(); String getName();
public abstract String getDescription(); String getDescription();
public abstract String getCurrencyCode(); String getCurrencyCode();
public abstract Integer getDigitsAfterDecimal(); Integer getDigitsAfterDecimal();
public abstract Integer getRepaymentEvery(); Integer getRepaymentEvery();
public abstract Integer getRepaymentFrequency(); Integer getRepaymentFrequency();
public abstract Boolean isFlexibleRepaymentSchedule(); Boolean isFlexibleRepaymentSchedule();
public abstract Boolean isInterestRebateAllowed(); Boolean isInterestRebateAllowed();
public abstract BigDecimal getPrincipal(); BigDecimal getPrincipal();
public abstract Boolean getFlexibleRepaymentSchedule(); Boolean getFlexibleRepaymentSchedule();
public abstract Boolean getInterestRebateAllowed(); Boolean getInterestRebateAllowed();
public abstract Integer getInterestRateFrequencyMethod(); Integer getInterestRateFrequencyMethod();
public abstract Integer getInterestMethod(); Integer getInterestMethod();
public abstract Integer getAmortizationMethod(); Integer getAmortizationMethod();
public abstract Integer getNumberOfRepayments(); Integer getNumberOfRepayments();
public abstract BigDecimal getInterestRatePerPeriod(); BigDecimal getInterestRatePerPeriod();
public abstract CommonLoanProperties getCommonLoanProperties(); CommonLoanProperties getCommonLoanProperties();
public abstract BigDecimal getInArrearsToleranceAmount(); BigDecimal getInArrearsToleranceAmount();
Integer getInterestCalculationPeriodMethod();
} }
@@ -37,7 +37,7 @@ public class SubmitLoanApplicationCommand {
final LocalDate interestCalculatedFromDate, final LocalDate interestCalculatedFromDate,
final LoanSchedule loanSchedule, final String currencyCode, final LoanSchedule loanSchedule, final String currencyCode,
final Integer digitsAfterDecimal, final Number principal, final Integer digitsAfterDecimal, final Number principal,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod,
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount, final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount,
final boolean flexibleRepaymentSchedule, final boolean flexibleRepaymentSchedule,
final boolean interestRebateAllowed) { final boolean interestRebateAllowed) {
@@ -46,7 +46,8 @@ public class SubmitLoanApplicationCommand {
this.submittedOnDate = submittedOnDate; this.submittedOnDate = submittedOnDate;
this.submittedOnNote = submittedOnNote; this.submittedOnNote = submittedOnNote;
commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod,
interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed); repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementDate = expectedDisbursementDate;
@@ -249,4 +250,12 @@ public class SubmitLoanApplicationCommand {
public void setInterestCalculatedFromDate(LocalDate interestCalculatedFromDate) { public void setInterestCalculatedFromDate(LocalDate interestCalculatedFromDate) {
this.interestCalculatedFromDate = interestCalculatedFromDate; this.interestCalculatedFromDate = interestCalculatedFromDate;
} }
public Integer getInterestCalculationPeriodMethod() {
return this.commonLoanProperties.getInterestCalculationPeriodMethod();
}
public void setInterestCalculationPeriodMethod(final Integer interestCalculationPeriodMethod) {
this.commonLoanProperties.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
}
} }
@@ -21,14 +21,15 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
public UpdateLoanProductCommand(final String currencyCode, public UpdateLoanProductCommand(final String currencyCode,
final Integer digitsAfterDecimal, final Number principal, final Integer digitsAfterDecimal, final Number principal,
final String name, final String description, final String name, final String description,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod,
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount, final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount,
final boolean flexibleRepaymentSchedule, final boolean flexibleRepaymentSchedule,
final boolean interestRebateAllowed) { final boolean interestRebateAllowed) {
this.name = name; this.name = name;
this.description = description; this.description = description;
commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod,
interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed); repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
} }
@@ -184,4 +185,13 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
public void setExternalId(String externalId) { public void setExternalId(String externalId) {
this.externalId = externalId; this.externalId = externalId;
} }
@Override
public Integer getInterestCalculationPeriodMethod() {
return this.commonLoanProperties.getInterestCalculationPeriodMethod();
}
public void setInterestCalculationPeriodMethod(final Integer interestCalculationPeriodMethod) {
this.commonLoanProperties.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
}
} }
+3 -5
View File
@@ -471,6 +471,7 @@ CREATE TABLE `portfolio_product_loan` (
`interest_period_frequency_enum` smallint(5) NOT NULL, `interest_period_frequency_enum` smallint(5) NOT NULL,
`annual_nominal_interest_rate` decimal(19,6) NOT NULL, `annual_nominal_interest_rate` decimal(19,6) NOT NULL,
`interest_method_enum` smallint(5) NOT NULL, `interest_method_enum` smallint(5) NOT NULL,
`interest_calculated_in_period_enum` smallint(5) NOT NULL DEFAULT 1,
`repay_every` smallint(5) NOT NULL, `repay_every` smallint(5) NOT NULL,
`repayment_period_frequency_enum` smallint(5) NOT NULL, `repayment_period_frequency_enum` smallint(5) NOT NULL,
`number_of_repayments` smallint(5) NOT NULL, `number_of_repayments` smallint(5) NOT NULL,
@@ -483,11 +484,7 @@ CREATE TABLE `portfolio_product_loan` (
`lastmodifiedby_id` bigint(20) DEFAULT NULL, `lastmodifiedby_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `FK1BD0772854DF2770` (`org_id`), KEY `FK1BD0772854DF2770` (`org_id`),
KEY `FKAUD0000000000003` (`createdby_id`), CONSTRAINT `FK1BD0772854DF2770` FOREIGN KEY (`org_id`) REFERENCES `org_organisation` (`id`)
KEY `FKAUD0000000000004` (`lastmodifiedby_id`),
CONSTRAINT `FK1BD0772854DF2770` FOREIGN KEY (`org_id`) REFERENCES `org_organisation` (`id`),
CONSTRAINT `FKAUD0000000000003` FOREIGN KEY (`createdby_id`) REFERENCES `admin_appuser` (`id`),
CONSTRAINT `FKAUD0000000000004` FOREIGN KEY (`lastmodifiedby_id`) REFERENCES `admin_appuser` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@@ -512,6 +509,7 @@ CREATE TABLE `portfolio_loan` (
`interest_period_frequency_enum` smallint(5) NOT NULL, `interest_period_frequency_enum` smallint(5) NOT NULL,
`annual_nominal_interest_rate` decimal(19,6) NOT NULL, `annual_nominal_interest_rate` decimal(19,6) NOT NULL,
`interest_method_enum` smallint(5) NOT NULL, `interest_method_enum` smallint(5) NOT NULL,
`interest_calculated_in_period_enum` smallint(5) NOT NULL DEFAULT 1,
`repay_every` smallint(5) NOT NULL, `repay_every` smallint(5) NOT NULL,
`repayment_period_frequency_enum` smallint(5) NOT NULL, `repayment_period_frequency_enum` smallint(5) NOT NULL,
`number_of_repayments` smallint(5) NOT NULL, `number_of_repayments` smallint(5) NOT NULL,
@@ -1,3 +1,14 @@
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
INSERT INTO `admin_oauth_consumer_application` VALUES (1,'mifosng-ui-consumer-key','testmifosng','MifosNG: Individual Lending', 'Provides capabilities specific to the individual lending credit methodology. Specifically capture of new customer information, loan appraisal, cashflow analysis, loan disbursement, loan monitoring etc', 'Mifos Community', 'http://localhost:8080/mifosng-individual-lending-app/', 'Individual Lending Data', 'Portfolio information for individual clients and loans.'); INSERT INTO `admin_oauth_consumer_application` VALUES (1,'mifosng-ui-consumer-key','testmifosng','MifosNG: Individual Lending', 'Provides capabilities specific to the individual lending credit methodology. Specifically capture of new customer information, loan appraisal, cashflow analysis, loan disbursement, loan monitoring etc', 'Mifos Community', 'http://localhost:8080/mifosng-individual-lending-app/', 'Individual Lending Data', 'Portfolio information for individual clients and loans.');
INSERT INTO `ref_loan_status` INSERT INTO `ref_loan_status`
@@ -13,19 +24,28 @@ VALUES
INSERT INTO `ref_currency` INSERT INTO `ref_currency`
(`id`,`code`,`decimal_places`,`display_symbol`,`name`, `internationalized_name_code`) (`id`,`code`,`decimal_places`,`display_symbol`,`name`, `internationalized_name_code`)
VALUES (1,'AED',2,NULL,'UAE Dirham','currency.AED'),(2,'AFN',2,NULL,'Afghanistan Afghani','currency.AFN'),(3,'ALL',2,NULL,'Albanian Lek','currency.ALL'),(4,'AMD',2,NULL,'Armenian Dram','currency.AMD'),(5,'ANG',2,NULL,'Netherlands Antillian Guilder','currency.ANG'),(6,'AOA',2,NULL,'Angolan Kwanza','currency.AOA'),(7,'ARS',2,NULL,'Argentine Peso','currency.ARS'),(8,'AUD',2,NULL,'Australian Dollar','currency.AUD'),(9,'AWG',2,NULL,'Aruban Guilder','currency.AWG'),(10,'AZM',2,NULL,'Azerbaijanian Manat','currency.AZM'),(11,'BAM',2,NULL,'Bosnia and Herzegovina Convertible Marks','currency.BAM'), VALUES
(12,'BBD',2,NULL,'Barbados Dollar','currency.BBD'),(13,'BDT',2,NULL,'Bangladesh Taka','currency.BDT'),(14,'BGN',2,NULL,'Bulgarian Lev','currency.BGN'),(15,'BHD',3,NULL,'Bahraini Dinar','currency.BHD'),(16,'BIF',0,NULL,'Burundi Franc','currency.BIF'),(17,'BMD',2,NULL,'Bermudian Dollar','currency.BMD'),(18,'BND',2,'B$','Brunei Dollar','currency.BND'), (1,'AED',2,NULL,'UAE Dirham','currency.AED'),
(2,'AFN',2,NULL,'Afghanistan Afghani','currency.AFN'),
(3,'ALL',2,NULL,'Albanian Lek','currency.ALL'),(4,'AMD',2,NULL,'Armenian Dram','currency.AMD'),(5,'ANG',2,NULL,'Netherlands Antillian Guilder','currency.ANG'),(6,'AOA',2,NULL,'Angolan Kwanza','currency.AOA'),(7,'ARS',2,NULL,'Argentine Peso','currency.ARS'),(8,'AUD',2,NULL,'Australian Dollar','currency.AUD'),(9,'AWG',2,NULL,'Aruban Guilder','currency.AWG'),(10,'AZM',2,NULL,'Azerbaijanian Manat','currency.AZM'),(11,'BAM',2,NULL,'Bosnia and Herzegovina Convertible Marks','currency.BAM'),
(12,'BBD',2,NULL,'Barbados Dollar','currency.BBD'),(13,'BDT',2,NULL,'Bangladesh Taka','currency.BDT'),(14,'BGN',2,NULL,'Bulgarian Lev','currency.BGN'),(15,'BHD',3,NULL,'Bahraini Dinar','currency.BHD'),(16,'BIF',0,NULL,'Burundi Franc','currency.BIF'),(17,'BMD',2,NULL,'Bermudian Dollar','currency.BMD'),
(18,'BND',2,'B$','Brunei Dollar','currency.BND'),
(19,'BOB',2,NULL,'Bolivian Boliviano','currency.BOB'),(20,'BRL',2,NULL,'Brazilian Real','currency.BRL'),(21,'BSD',2,NULL,'Bahamian Dollar','currency.BSD'),(22,'BTN',2,NULL,'Bhutan Ngultrum','currency.BTN'),(23,'BWP',2,NULL,'Botswana Pula','currency.BWP'),(24,'BYR',0,NULL,'Belarussian Ruble','currency.BYR'),(25,'BZD',2,NULL,'Belize Dollar','currency.BZD'),(26,'CAD',2,NULL,'Canadian Dollar','currency.CAD'), (19,'BOB',2,NULL,'Bolivian Boliviano','currency.BOB'),(20,'BRL',2,NULL,'Brazilian Real','currency.BRL'),(21,'BSD',2,NULL,'Bahamian Dollar','currency.BSD'),(22,'BTN',2,NULL,'Bhutan Ngultrum','currency.BTN'),(23,'BWP',2,NULL,'Botswana Pula','currency.BWP'),(24,'BYR',0,NULL,'Belarussian Ruble','currency.BYR'),(25,'BZD',2,NULL,'Belize Dollar','currency.BZD'),(26,'CAD',2,NULL,'Canadian Dollar','currency.CAD'),
(27,'CDF',2,NULL,'Franc Congolais','currency.CDF'),(28,'CHF',2,NULL,'Swiss Franc','currency.CHF'),(29,'CLP',0,NULL,'Chilean Peso','currency.CLP'),(30,'CNY',2,NULL,'Chinese Yuan Renminbi','currency.CNY'),(31,'COP',2,NULL,'Colombian Peso','currency.COP'),(32,'CRC',2,NULL,'Costa Rican Colon','currency.CRC'),(33,'CSD',2,NULL,'Serbian Dinar','currency.CSD'),(34,'CUP',2,NULL,'Cuban Peso','currency.CUP'),(35,'CVE',2,NULL,'Cape Verde Escudo','currency.CVE'), (27,'CDF',2,NULL,'Franc Congolais','currency.CDF'),(28,'CHF',2,NULL,'Swiss Franc','currency.CHF'),(29,'CLP',0,NULL,'Chilean Peso','currency.CLP'),(30,'CNY',2,NULL,'Chinese Yuan Renminbi','currency.CNY'),(31,'COP',2,NULL,'Colombian Peso','currency.COP'),(32,'CRC',2,NULL,'Costa Rican Colon','currency.CRC'),(33,'CSD',2,NULL,'Serbian Dinar','currency.CSD'),(34,'CUP',2,NULL,'Cuban Peso','currency.CUP'),(35,'CVE',2,NULL,'Cape Verde Escudo','currency.CVE'),
(36,'CYP',2,NULL,'Cyprus Pound','currency.CYP'),(37,'CZK',2,NULL,'Czech Koruna','currency.CZK'),(38,'DJF',0,NULL,'Djibouti Franc','currency.DJF'),(39,'DKK',2,NULL,'Danish Krone','currency.DKK'),(40,'DOP',2,NULL,'Dominican Peso','currency.DOP'),(41,'DZD',2,NULL,'Algerian Dinar','currency.DZD'),(42,'EEK',2,NULL,'Estonian Kroon','currency.EEK'),(43,'EGP',2,NULL,'Egyptian Pound','currency.EGP'),(44,'ERN',2,NULL,'Eritrea Nafka','currency.ERN'),(45,'ETB',2,NULL,'Ethiopian Birr','currency.ETB'),(46,'EUR',2,NULL,'euro','currency.EUR'),(47,'FJD',2,NULL,'Fiji Dollar','currency.FJD'),(48,'FKP',2,NULL,'Falkland Islands Pound','currency.FKP'),(49,'GBP',2,NULL,'Pound Sterling','currency.GBP'),(50,'GEL',2,NULL,'Georgian Lari','currency.GEL'), (36,'CYP',2,NULL,'Cyprus Pound','currency.CYP'),(37,'CZK',2,NULL,'Czech Koruna','currency.CZK'),(38,'DJF',0,NULL,'Djibouti Franc','currency.DJF'),(39,'DKK',2,NULL,'Danish Krone','currency.DKK'),(40,'DOP',2,NULL,'Dominican Peso','currency.DOP'),(41,'DZD',2,NULL,'Algerian Dinar','currency.DZD'),(42,'EEK',2,NULL,'Estonian Kroon','currency.EEK'),(43,'EGP',2,NULL,'Egyptian Pound','currency.EGP'),(44,'ERN',2,NULL,'Eritrea Nafka','currency.ERN'),(45,'ETB',2,NULL,'Ethiopian Birr','currency.ETB'),(46,'EUR',2,NULL,'euro','currency.EUR'),(47,'FJD',2,NULL,'Fiji Dollar','currency.FJD'),(48,'FKP',2,NULL,'Falkland Islands Pound','currency.FKP'),(49,'GBP',2,NULL,'Pound Sterling','currency.GBP'),(50,'GEL',2,NULL,'Georgian Lari','currency.GEL'),
(51,'GHC',2,'GHc','Ghana Cedi','currency.GHC'), (51,'GHC',2,'GHc','Ghana Cedi','currency.GHC'),
(52,'GIP',2,NULL,'Gibraltar Pound','currency.GIP'),(53,'GMD',2,NULL,'Gambian Dalasi','currency.GMD'),(54,'GNF',0,NULL,'Guinea Franc','currency.GNF'),(55,'GTQ',2,NULL,'Guatemala Quetzal','currency.GTQ'),(56,'GYD',2,NULL,'Guyana Dollar','currency.GYD'),(57,'HKD',2,NULL,'Hong Kong Dollar','currency.HKD'),(58,'HNL',2,NULL,'Honduras Lempira','currency.HNL'),(59,'HRK',2,NULL,'Croatian Kuna','currency.HRK'),(60,'HTG',2,NULL,'Haiti Gourde','currency.HTG'),(61,'HUF',2,NULL,'Hungarian Forint','currency.HUF'),(62,'IDR',2,NULL,'Indonesian Rupiah','currency.IDR'),(63,'ILS',2,NULL,'New Israeli Shekel','currency.ILS'),(64,'INR',2,NULL,'Indian Rupee','currency.INR'),(65,'IQD',3,NULL,'Iraqi Dinar','currency.IQD'),(66,'IRR',2,NULL,'Iranian Rial','currency.IRR'),(67,'ISK',0,NULL,'Iceland Krona','currency.ISK'),(68,'JMD',2,NULL,'Jamaican Dollar','currency.JMD'),(69,'JOD',3,NULL,'Jordanian Dinar','currency.JOD'),(70,'JPY',0,NULL,'Japanese Yen','currency.JPY'), (52,'GIP',2,NULL,'Gibraltar Pound','currency.GIP'),(53,'GMD',2,NULL,'Gambian Dalasi','currency.GMD'),(54,'GNF',0,NULL,'Guinea Franc','currency.GNF'),(55,'GTQ',2,NULL,'Guatemala Quetzal','currency.GTQ'),(56,'GYD',2,NULL,'Guyana Dollar','currency.GYD'),(57,'HKD',2,NULL,'Hong Kong Dollar','currency.HKD'),(58,'HNL',2,NULL,'Honduras Lempira','currency.HNL'),(59,'HRK',2,NULL,'Croatian Kuna','currency.HRK'),(60,'HTG',2,NULL,'Haiti Gourde','currency.HTG'),(61,'HUF',2,NULL,'Hungarian Forint','currency.HUF'),(62,'IDR',2,NULL,'Indonesian Rupiah','currency.IDR'),(63,'ILS',2,NULL,'New Israeli Shekel','currency.ILS'),(64,'INR',2,NULL,'Indian Rupee','currency.INR'),(65,'IQD',3,NULL,'Iraqi Dinar','currency.IQD'),(66,'IRR',2,NULL,'Iranian Rial','currency.IRR'),(67,'ISK',0,NULL,'Iceland Krona','currency.ISK'),(68,'JMD',2,NULL,'Jamaican Dollar','currency.JMD'),(69,'JOD',3,NULL,'Jordanian Dinar','currency.JOD'),(70,'JPY',0,NULL,'Japanese Yen','currency.JPY'),
(71,'KES',2,'KSh','Kenyan Shilling','currency.KES'), (71,'KES',2,'KSh','Kenyan Shilling','currency.KES'),
(72,'KGS',2,NULL,'Kyrgyzstan Som','currency.KGS'),(73,'KHR',2,NULL,'Cambodia Riel','currency.KHR'),(74,'KMF',0,NULL,'Comoro Franc','currency.KMF'),(75,'KPW',2,NULL,'North Korean Won','currency.KPW'),(76,'KRW',0,NULL,'Korean Won','currency.KRW'),(77,'KWD',3,NULL,'Kuwaiti Dinar','currency.KWD'),(78,'KYD',2,NULL,'Cayman Islands Dollar','currency.KYD'),(79,'KZT',2,NULL,'Kazakhstan Tenge','currency.KZT'),(80,'LAK',2,NULL,'Lao Kip','currency.LAK'),(81,'LBP',2,NULL,'Lebanese Pound','currency.LBP'),(82,'LKR',2,NULL,'Sri Lanka Rupee','currency.LKR'),(83,'LRD',2,NULL,'Liberian Dollar','currency.LRD'),(84,'LSL',2,NULL,'Lesotho Loti','currency.LSL'), (72,'KGS',2,NULL,'Kyrgyzstan Som','currency.KGS'),(73,'KHR',2,NULL,'Cambodia Riel','currency.KHR'),(74,'KMF',0,NULL,'Comoro Franc','currency.KMF'),(75,'KPW',2,NULL,'North Korean Won','currency.KPW'),(76,'KRW',0,NULL,'Korean Won','currency.KRW'),(77,'KWD',3,NULL,'Kuwaiti Dinar','currency.KWD'),(78,'KYD',2,NULL,'Cayman Islands Dollar','currency.KYD'),(79,'KZT',2,NULL,'Kazakhstan Tenge','currency.KZT'),
(80,'LAK',2,NULL,'Lao Kip','currency.LAK'),
(81,'LBP',2,'L£','Lebanese Pound','currency.LBP'),
(82,'LKR',2,NULL,'Sri Lanka Rupee','currency.LKR'),(83,'LRD',2,NULL,'Liberian Dollar','currency.LRD'),(84,'LSL',2,NULL,'Lesotho Loti','currency.LSL'),
(85,'LTL',2,NULL,'Lithuanian Litas','currency.LTL'),(86,'LVL',2,NULL,'Latvian Lats','currency.LVL'),(87,'LYD',3,NULL,'Libyan Dinar','currency.LYD'),(88,'MAD',2,NULL,'Moroccan Dirham','currency.MAD'),(89,'MDL',2,NULL,'Moldovan Leu','currency.MDL'),(90,'MGA',2,NULL,'Malagasy Ariary','currency.MGA'),(91,'MKD',2,NULL,'Macedonian Denar','currency.MKD'),(92,'MMK',2,NULL,'Myanmar Kyat','currency.MMK'),(93,'MNT',2,NULL,'Mongolian Tugrik','currency.MNT'),(94,'MOP',2,NULL,'Macau Pataca','currency.MOP'),(95,'MRO',2,NULL,'Mauritania Ouguiya','currency.MRO'),(96,'MTL',2,NULL,'Maltese Lira','currency.MTL'),(97,'MUR',2,NULL,'Mauritius Rupee','currency.MUR'),(98,'MVR',2,NULL,'Maldives Rufiyaa','currency.MVR'),(99,'MWK',2,NULL,'Malawi Kwacha','currency.MWK'),(100,'MXN',2,NULL,'Mexican Peso','currency.MXN'),(101,'MYR',2,NULL,'Malaysian Ringgit','currency.MYR'),(102,'MZM',2,NULL,'Mozambique Metical','currency.MZM'),(103,'NAD',2,NULL,'Namibia Dollar','currency.NAD'),(104,'NGN',2,NULL,'Nigerian Naira','currency.NGN'),(105,'NIO',2,NULL,'Nicaragua Cordoba Oro','currency.NIO'),(106,'NOK',2,NULL,'Norwegian Krone','currency.NOK'),(107,'NPR',2,NULL,'Nepalese Rupee','currency.NPR'),(108,'NZD',2,NULL,'New Zealand Dollar','currency.NZD'),(109,'OMR',3,NULL,'Rial Omani','currency.OMR'),(110,'PAB',2,NULL,'Panama Balboa','currency.PAB'),(111,'PEN',2,NULL,'Peruvian Nuevo Sol','currency.PEN'),(112,'PGK',2,NULL,'Papua New Guinea Kina','currency.PGK'),(113,'PHP',2,NULL,'Philippine Peso','currency.PHP'),(114,'PKR',2,NULL,'Pakistan Rupee','currency.PKR'),(115,'PLN',2,NULL,'Polish Zloty','currency.PLN'),(116,'PYG',0,NULL,'Paraguayan Guarani','currency.PYG'),(117,'QAR',2,NULL,'Qatari Rial','currency.QAR'), (85,'LTL',2,NULL,'Lithuanian Litas','currency.LTL'),(86,'LVL',2,NULL,'Latvian Lats','currency.LVL'),(87,'LYD',3,NULL,'Libyan Dinar','currency.LYD'),(88,'MAD',2,NULL,'Moroccan Dirham','currency.MAD'),(89,'MDL',2,NULL,'Moldovan Leu','currency.MDL'),(90,'MGA',2,NULL,'Malagasy Ariary','currency.MGA'),(91,'MKD',2,NULL,'Macedonian Denar','currency.MKD'),(92,'MMK',2,NULL,'Myanmar Kyat','currency.MMK'),(93,'MNT',2,NULL,'Mongolian Tugrik','currency.MNT'),(94,'MOP',2,NULL,'Macau Pataca','currency.MOP'),(95,'MRO',2,NULL,'Mauritania Ouguiya','currency.MRO'),(96,'MTL',2,NULL,'Maltese Lira','currency.MTL'),(97,'MUR',2,NULL,'Mauritius Rupee','currency.MUR'),(98,'MVR',2,NULL,'Maldives Rufiyaa','currency.MVR'),(99,'MWK',2,NULL,'Malawi Kwacha','currency.MWK'),(100,'MXN',2,NULL,'Mexican Peso','currency.MXN'),(101,'MYR',2,NULL,'Malaysian Ringgit','currency.MYR'),(102,'MZM',2,NULL,'Mozambique Metical','currency.MZM'),(103,'NAD',2,NULL,'Namibia Dollar','currency.NAD'),(104,'NGN',2,NULL,'Nigerian Naira','currency.NGN'),(105,'NIO',2,NULL,'Nicaragua Cordoba Oro','currency.NIO'),(106,'NOK',2,NULL,'Norwegian Krone','currency.NOK'),(107,'NPR',2,NULL,'Nepalese Rupee','currency.NPR'),(108,'NZD',2,NULL,'New Zealand Dollar','currency.NZD'),(109,'OMR',3,NULL,'Rial Omani','currency.OMR'),(110,'PAB',2,NULL,'Panama Balboa','currency.PAB'),(111,'PEN',2,NULL,'Peruvian Nuevo Sol','currency.PEN'),(112,'PGK',2,NULL,'Papua New Guinea Kina','currency.PGK'),(113,'PHP',2,NULL,'Philippine Peso','currency.PHP'),(114,'PKR',2,NULL,'Pakistan Rupee','currency.PKR'),(115,'PLN',2,NULL,'Polish Zloty','currency.PLN'),(116,'PYG',0,NULL,'Paraguayan Guarani','currency.PYG'),(117,'QAR',2,NULL,'Qatari Rial','currency.QAR'),
(118,'RON',2,NULL,'Romanian Leu','currency.RON'),(119,'RUB',2,NULL,'Russian Ruble','currency.RUB'),(120,'RWF',0,NULL,'Rwanda Franc','currency.RWF'),(121,'SAR',2,NULL,'Saudi Riyal','currency.SAR'),(122,'SBD',2,NULL,'Solomon Islands Dollar','currency.SBD'),(123,'SCR',2,NULL,'Seychelles Rupee','currency.SCR'),(124,'SDD',2,NULL,'Sudanese Dinar','currency.SDD'),(125,'SEK',2,NULL,'Swedish Krona','currency.SEK'),(126,'SGD',2,NULL,'Singapore Dollar','currency.SGD'),(127,'SHP',2,NULL,'St Helena Pound','currency.SHP'),(128,'SIT',2,NULL,'Slovenian Tolar','currency.SIT'),(129,'SKK',2,NULL,'Slovak Koruna','currency.SKK'),(130,'SLL',2,NULL,'Sierra Leone Leone','currency.SLL'),(131,'SOS',2,NULL,'Somali Shilling','currency.SOS'),(132,'SRD',2,NULL,'Surinam Dollar','currency.SRD'), (118,'RON',2,NULL,'Romanian Leu','currency.RON'),(119,'RUB',2,NULL,'Russian Ruble','currency.RUB'),(120,'RWF',0,NULL,'Rwanda Franc','currency.RWF'),(121,'SAR',2,NULL,'Saudi Riyal','currency.SAR'),(122,'SBD',2,NULL,'Solomon Islands Dollar','currency.SBD'),(123,'SCR',2,NULL,'Seychelles Rupee','currency.SCR'),(124,'SDD',2,NULL,'Sudanese Dinar','currency.SDD'),(125,'SEK',2,NULL,'Swedish Krona','currency.SEK'),(126,'SGD',2,NULL,'Singapore Dollar','currency.SGD'),(127,'SHP',2,NULL,'St Helena Pound','currency.SHP'),(128,'SIT',2,NULL,'Slovenian Tolar','currency.SIT'),(129,'SKK',2,NULL,'Slovak Koruna','currency.SKK'),(130,'SLL',2,NULL,'Sierra Leone Leone','currency.SLL'),(131,'SOS',2,NULL,'Somali Shilling','currency.SOS'),(132,'SRD',2,NULL,'Surinam Dollar','currency.SRD'),
(133,'STD',2,NULL,'Sao Tome and Principe Dobra','currency.STD'),(134,'SVC',2,NULL,'El Salvador Colon','currency.SVC'),(135,'SYP',2,NULL,'Syrian Pound','currency.SYP'),(136,'SZL',2,NULL,'Swaziland Lilangeni','currency.SZL'),(137,'THB',2,NULL,'Thai Baht','currency.THB'), (133,'STD',2,NULL,'Sao Tome and Principe Dobra','currency.STD'),(134,'SVC',2,NULL,'El Salvador Colon','currency.SVC'),(135,'SYP',2,NULL,'Syrian Pound','currency.SYP'),(136,'SZL',2,NULL,'Swaziland Lilangeni','currency.SZL'),(137,'THB',2,NULL,'Thai Baht','currency.THB'),
(138,'TJS',2,NULL,'Tajik Somoni','currency.TJS'),(139,'TMM',2,NULL,'Turkmenistan Manat','currency.TMM'),(140,'TND',3,NULL,'Tunisian Dinar','currency.TND'),(141,'TOP',2,NULL,'Tonga Pa\'anga','currency.TOP'),(142,'TRY',2,NULL,'Turkish Lira','currency.TRY'),(143,'TTD',2,NULL,'Trinidad and Tobago Dollar','currency.TTD'),(144,'TWD',2,NULL,'New Taiwan Dollar','currency.TWD'),(145,'TZS',2,NULL,'Tanzanian Shilling','currency.TZS'),(146,'UAH',2,NULL,'Ukraine Hryvnia','currency.UAH'),(147,'UGX',2,NULL,'Uganda Shilling','currency.UGX'), (138,'TJS',2,NULL,'Tajik Somoni','currency.TJS'),(139,'TMM',2,NULL,'Turkmenistan Manat','currency.TMM'),
(140,'TND',3,'DT','Tunisian Dinar','currency.TND'),
(141,'TOP',2,NULL,'Tonga Pa\'anga','currency.TOP'),(142,'TRY',2,NULL,'Turkish Lira','currency.TRY'),(143,'TTD',2,NULL,'Trinidad and Tobago Dollar','currency.TTD'),(144,'TWD',2,NULL,'New Taiwan Dollar','currency.TWD'),(145,'TZS',2,NULL,'Tanzanian Shilling','currency.TZS'),(146,'UAH',2,NULL,'Ukraine Hryvnia','currency.UAH'),(147,'UGX',2,NULL,'Uganda Shilling','currency.UGX'),
(148,'USD',2,'$','US Dollar','currency.USD'), (148,'USD',2,'$','US Dollar','currency.USD'),
(149,'UYU',2,NULL,'Peso Uruguayo','currency.UYU'),(150,'UZS',2,NULL,'Uzbekistan Sum','currency.UZS'),(151,'VEB',2,NULL,'Venezuelan Bolivar','currency.VEB'),(152,'VND',2,NULL,'Vietnamese Dong','currency.VND'),(153,'VUV',0,NULL,'Vanuatu Vatu','currency.VUV'),(154,'WST',2,NULL,'Samoa Tala','currency.WST'),(155,'XAF',0,NULL,'CFA Franc BEAC','currency.XAF'),(156,'XCD',2,NULL,'East Caribbean Dollar','currency.XCD'),(157,'XDR',5,NULL,'SDR (Special Drawing Rights)','currency.XDR'), (149,'UYU',2,NULL,'Peso Uruguayo','currency.UYU'),(150,'UZS',2,NULL,'Uzbekistan Sum','currency.UZS'),(151,'VEB',2,NULL,'Venezuelan Bolivar','currency.VEB'),(152,'VND',2,NULL,'Vietnamese Dong','currency.VND'),(153,'VUV',0,NULL,'Vanuatu Vatu','currency.VUV'),(154,'WST',2,NULL,'Samoa Tala','currency.WST'),(155,'XAF',0,NULL,'CFA Franc BEAC','currency.XAF'),(156,'XCD',2,NULL,'East Caribbean Dollar','currency.XCD'),(157,'XDR',5,NULL,'SDR (Special Drawing Rights)','currency.XDR'),
(158,'XOF',0, 'CFA','CFA Franc BCEAO','currency.XOF'), (158,'XOF',0, 'CFA','CFA Franc BCEAO','currency.XOF'),
@@ -34,3 +54,15 @@ VALUES (1,'AED',2,NULL,'UAE Dirham','currency.AED'),(2,'AFN',2,NULL,'Afghanistan
(161,'ZAR',2,NULL,'South African Rand','currency.ZAR'), (161,'ZAR',2,NULL,'South African Rand','currency.ZAR'),
(162,'ZMK',2,NULL,'Zambian Kwacha','currency.ZMK'), (162,'ZMK',2,NULL,'Zambian Kwacha','currency.ZMK'),
(163,'ZWD',2,NULL,'Zimbabwe Dollar','currency.ZWD'); (163,'ZWD',2,NULL,'Zimbabwe Dollar','currency.ZWD');
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+3 -2
View File
@@ -125,6 +125,7 @@ INSERT INTO `mifosngprovider`.`portfolio_product_loan`
`interest_period_frequency_enum`, `interest_period_frequency_enum`,
`annual_nominal_interest_rate`, `annual_nominal_interest_rate`,
`interest_method_enum`, `interest_method_enum`,
`interest_calculated_in_period_enum`,
`repay_every`, `repay_every`,
`repayment_period_frequency_enum`, `repayment_period_frequency_enum`,
`number_of_repayments`, `number_of_repayments`,
@@ -136,7 +137,7 @@ INSERT INTO `mifosngprovider`.`portfolio_product_loan`
`lastmodified_date`, `lastmodified_date`,
`lastmodifiedby_id`) `lastmodifiedby_id`)
VALUES VALUES
(1,1,'XOF',0,'100000.000000','1000.000000','Agricultural Loan','An agricultural loan given to farmers to help buy crop, stock and machinery. With an arrears tolerance setting of 1,000 CFA, loans are not marked as \'in arrears\' or \'in bad standing\' if the amount outstanding is less than this. Interest rate is described using monthly percentage rate (MPR) even though the loan typically lasts a year and requires one repayment (typically at time when farmer sells crop)','1.750000',2,'21.000000',0,12,2,1,1,'\0','\0',1,'2012-04-12 22:14:34','2012-04-12 22:14:34',1); (1,1,'XOF',0,'100000.000000','1000.000000','Agricultural Loan','An agricultural loan given to farmers to help buy crop, stock and machinery. With an arrears tolerance setting of 1,000 CFA, loans are not marked as \'in arrears\' or \'in bad standing\' if the amount outstanding is less than this. Interest rate is described using monthly percentage rate (MPR) even though the loan typically lasts a year and requires one repayment (typically at time when farmer sells crop)','1.750000',2,'21.000000',0,1,12,2,1,1,'\0','\0',1,'2012-04-12 22:14:34','2012-04-12 22:14:34',1);
INSERT INTO `mifosngprovider`.`portfolio_client` INSERT INTO `mifosngprovider`.`portfolio_client`
@@ -181,7 +182,7 @@ VALUES
first five loans first for five clients first five loans first for five clients
*/ */
INSERT INTO `portfolio_loan` VALUES INSERT INTO `portfolio_loan` VALUES
(1,1,NULL,1,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,10,2,1,1,'\0','\0','0.000000','2009-01-05 12:33:10','2009-01-08 12:33:16','2009-01-15',NULL,NULL,'2009-01-15','2009-11-15',NULL,'2009-11-13 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 12:33:10','2012-04-13 12:34:40',1),(2,1,NULL,2,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,11,2,1,1,'\0','\0','0.000000','2009-01-08 13:08:16','2009-01-12 13:08:25','2009-01-15',NULL,NULL,'2009-01-15','2009-12-15','2009-12-15','2009-12-15 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:08:16','2012-04-13 13:11:53',1),(4,1,NULL,3,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,12,2,1,1,'\0','\0','0.000000','2009-01-13 13:14:30','2009-01-15 13:14:54','2009-01-22',NULL,NULL,'2009-01-22','2010-01-22','2010-01-07','2010-01-07 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:14:30','2012-04-13 13:15:32',1),(5,1,NULL,4,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,8,2,1,1,'\0','\0','0.000000','2009-01-12 13:23:32','2009-01-15 13:23:44','2009-01-22',NULL,NULL,'2009-01-22','2009-09-22','2009-09-22','2009-09-22 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:23:32','2012-04-13 13:24:01',1),(6,1,NULL,5,1,600,'XOF',0,'300000.000000','1000.000000','1.750000',2,'21.000000',0,3,2,4,1,'\0','\0','0.000000','2009-01-26 13:30:54','2009-01-27 13:31:02','2009-01-29','2009-05-01','2009-02-01','2009-01-29','2010-02-01','2010-02-01','2010-02-01 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:30:54','2012-04-13 13:33:05',1); (1,1,NULL,1,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,1,10,2,1,1,'\0','\0','0.000000','2009-01-05 12:33:10','2009-01-08 12:33:16','2009-01-15',NULL,NULL,'2009-01-15','2009-11-15',NULL,'2009-11-13 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 12:33:10','2012-04-13 12:34:40',1),(2,1,NULL,2,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,1,11,2,1,1,'\0','\0','0.000000','2009-01-08 13:08:16','2009-01-12 13:08:25','2009-01-15',NULL,NULL,'2009-01-15','2009-12-15','2009-12-15','2009-12-15 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:08:16','2012-04-13 13:11:53',1),(4,1,NULL,3,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,1,12,2,1,1,'\0','\0','0.000000','2009-01-13 13:14:30','2009-01-15 13:14:54','2009-01-22',NULL,NULL,'2009-01-22','2010-01-22','2010-01-07','2010-01-07 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:14:30','2012-04-13 13:15:32',1),(5,1,NULL,4,1,600,'XOF',0,'100000.000000','1000.000000','1.750000',2,'21.000000',0,1,8,2,1,1,'\0','\0','0.000000','2009-01-12 13:23:32','2009-01-15 13:23:44','2009-01-22',NULL,NULL,'2009-01-22','2009-09-22','2009-09-22','2009-09-22 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:23:32','2012-04-13 13:24:01',1),(6,1,NULL,5,1,600,'XOF',0,'300000.000000','1000.000000','1.750000',2,'21.000000',0,1,3,2,4,1,'\0','\0','0.000000','2009-01-26 13:30:54','2009-01-27 13:31:02','2009-01-29','2009-05-01','2009-02-01','2009-01-29','2010-02-01','2010-02-01','2010-02-01 00:00:00',NULL,NULL,NULL,NULL,1,'2012-04-13 13:30:54','2012-04-13 13:33:05',1);
INSERT INTO `portfolio_loan_repayment_schedule` VALUES INSERT INTO `portfolio_loan_repayment_schedule` VALUES
(1,1,1,'2009-11-15',1,'100000.000000','100000.000000','17500.000000','17500.000000','',1,'2012-04-13 12:33:11','2012-04-13 12:34:40',1), (1,1,1,'2009-11-15',1,'100000.000000','100000.000000','17500.000000','17500.000000','',1,'2012-04-13 12:33:11','2012-04-13 12:34:40',1),
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
/*
Note: its possible that this script wont apply on windowns through the command line client. The UTF-8 value £ isnt inserted.
In this case you can open up an sql tool like MySql workbench and apply this script in total.
*/
UPDATE `ref_currency` SET `display_symbol` = 'BND' where `id`=18;
UPDATE `ref_currency` SET `display_symbol` = 'GHC' where `id`=51;
UPDATE `ref_currency` SET `display_symbol` = 'KSh' where `id`=71;
UPDATE `ref_currency` SET `display_symbol` = 'DT' where `id`=140;
UPDATE `ref_currency` SET `display_symbol` = '$' where `id`=148;
UPDATE `mifosngprovider`.`ref_currency` SET `display_symbol`='L£' WHERE `id`='81';
@@ -0,0 +1,3 @@
ALTER TABLE `mifosngprovider`.`portfolio_product_loan` add column `interest_calculated_in_period_enum` smallint(5) NOT NULL DEFAULT 1;
ALTER TABLE `mifosngprovider`.`portfolio_loan` add column `interest_calculated_in_period_enum` smallint(5) NOT NULL DEFAULT 1;
@@ -128,6 +128,7 @@ public class LoanController {
@RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate, @RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate,
@RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod, @RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod,
@RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod, @RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestRateCalculatedInPeriod,
@RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr, @RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr,
@RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr, @RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr,
@RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr @RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr
@@ -146,7 +147,7 @@ public class LoanController {
final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate"); final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate");
CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod,
interestRateFrequencyMethod, interestMethod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, interestRateFrequencyMethod, interestMethod, interestRateCalculatedInPeriod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate); flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
LoanSchedule loanSchedule = this.commonRestOperations.calculateLoanSchedule(calculateLoanScheduleCommand); LoanSchedule loanSchedule = this.commonRestOperations.calculateLoanSchedule(calculateLoanScheduleCommand);
@@ -154,7 +155,7 @@ public class LoanController {
SubmitLoanApplicationCommand command = new SubmitLoanApplicationCommand(applicantId, productId, SubmitLoanApplicationCommand command = new SubmitLoanApplicationCommand(applicantId, productId,
submittedOnDate, submittedOnNote, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate, submittedOnDate, submittedOnNote, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate,
loanSchedule, currencyCode, digitsAfterDecimal, principal, loanSchedule, currencyCode, digitsAfterDecimal, principal,
interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, interestRateCalculatedInPeriod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed); toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
@@ -175,6 +176,7 @@ public class LoanController {
@RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate, @RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate,
@RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod, @RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod,
@RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod, @RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestRateCalculatedInPeriod,
@RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr, @RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr,
@RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr, @RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr,
@RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr @RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr
@@ -189,7 +191,7 @@ public class LoanController {
final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate"); final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate");
CalculateLoanScheduleCommand command = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, CalculateLoanScheduleCommand command = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod,
interestRateFrequencyMethod, interestMethod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, interestRateFrequencyMethod, interestMethod, interestRateCalculatedInPeriod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate); flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
return this.commonRestOperations.calculateLoanSchedule(command); return this.commonRestOperations.calculateLoanSchedule(command);
@@ -102,7 +102,8 @@ public class LoanProductController {
@RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber, @RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber,
@RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber, @RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber,
@RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency, @RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency,
@RequestParam("selectedInterestMethodOption") Integer interestMethod @RequestParam("selectedInterestMethodOption") Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestCalculationPeriodMethod
) { ) {
CreateLoanProductCommand command = new CreateLoanProductCommand(); CreateLoanProductCommand command = new CreateLoanProductCommand();
@@ -132,6 +133,7 @@ public class LoanProductController {
} }
command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency); command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency);
command.setInterestMethod(interestMethod); command.setInterestMethod(interestMethod);
command.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
return this.commonRestOperations.createLoanProduct(command); return this.commonRestOperations.createLoanProduct(command);
} }
@@ -155,7 +157,8 @@ public class LoanProductController {
@RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber, @RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber,
@RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber, @RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber,
@RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency, @RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency,
@RequestParam("selectedInterestMethodOption") Integer interestMethod @RequestParam("selectedInterestMethodOption") Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestCalculationPeriodMethod
) { ) {
UpdateLoanProductCommand command = new UpdateLoanProductCommand(); UpdateLoanProductCommand command = new UpdateLoanProductCommand();
@@ -187,6 +190,7 @@ public class LoanProductController {
} }
command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency); command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency);
command.setInterestMethod(interestMethod); command.setInterestMethod(interestMethod);
command.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
return this.commonRestOperations.updateLoanProduct(command); return this.commonRestOperations.updateLoanProduct(command);
} }
@@ -237,6 +237,7 @@ form.label.loan.product.amortization=Amortization:
form.label.loan.product.arrears.tolerance=Arrears tolerance: form.label.loan.product.arrears.tolerance=Arrears tolerance:
form.label.loan.product.nominal.interestrate=Nominal interest rate %: form.label.loan.product.nominal.interestrate=Nominal interest rate %:
form.label.loan.product.interest.method=Interest method: form.label.loan.product.interest.method=Interest method:
form.label.loan.product.interest.rate.calcutated.in.period=Interest calculation period:
validation.msg.product.name.cannot.be.blank=Product name cannot be blank. validation.msg.product.name.cannot.be.blank=Product name cannot be blank.
validation.msg.product.description.exceeds.max.length=The content of the description has exceeded max allowed length of 500 characters. validation.msg.product.description.exceeds.max.length=The content of the description has exceeded max allowed length of 500 characters.
@@ -236,6 +236,7 @@ form.label.loan.product.amortization=Amortization:(fr)
form.label.loan.product.arrears.tolerance=Arrears tolerance:(fr) form.label.loan.product.arrears.tolerance=Arrears tolerance:(fr)
form.label.loan.product.nominal.interestrate=Nominal interest rate %:(fr) form.label.loan.product.nominal.interestrate=Nominal interest rate %:(fr)
form.label.loan.product.interest.method=Interest method:(fr) form.label.loan.product.interest.method=Interest method:(fr)
form.label.loan.product.interest.rate.calcutated.in.period=Interest calculation period:(fr)
validation.msg.product.name.cannot.be.blank=Product name cannot be blank.(fr) validation.msg.product.name.cannot.be.blank=Product name cannot be blank.(fr)
validation.msg.product.description.exceeds.max.length=The content of the description has exceeded max allowed length of 500 characters.(fr) validation.msg.product.description.exceeds.max.length=The content of the description has exceeded max allowed length of 500 characters.(fr)
@@ -82,26 +82,6 @@
<input id="numberOfRepayments" name="numberOfRepayments" title="" style="width: 50px;" value="{{=$ctx.number(numberOfRepayments)}}"/> <input id="numberOfRepayments" name="numberOfRepayments" title="" style="width: 50px;" value="{{=$ctx.number(numberOfRepayments)}}"/>
</td> </td>
</tr> </tr>
<tr>
<td><spring:message code="form.label.loan.product.amortization"/></td>
<td>
<select id="selectedAmortizationMethodOption" name="selectedAmortizationMethodOption" title="" style="width: 178px;">
{{#each possibleAmortizationOptions}}
{{#if $ctx.number($parent.parent.data.amortizationMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
{{#else}}
<option value="{{=$ctx.number(id)}}">{{=value}}</option>
{{/if}}
{{/each}}
</select>
</td>
</tr>
<tr>
<td><spring:message code="form.label.loan.product.arrears.tolerance"/></td>
<td>
<input id="inArrearsTolerance" name="inArrearsTolerance" title="" style="width: 125px;" value="{{=$ctx.money(inArrearsTolerance)}}" />
</td>
</tr>
</table> </table>
</td> </td>
<td valign="top" style="padding-left: 5px; padding-right: 5px; border-right: 1px solid;"> <td valign="top" style="padding-left: 5px; padding-right: 5px; border-right: 1px solid;">
@@ -109,15 +89,29 @@
<tr> <tr>
<td><spring:message code="form.label.loan.product.nominal.interestrate"/></td> <td><spring:message code="form.label.loan.product.nominal.interestrate"/></td>
<td> <td>
<input id="nominalInterestRate" name="nominalInterestRate" title="" style="width: 60px;" value="{{=$ctx.decimal(interestRatePerPeriod, 4)}}" /> <input id="nominalInterestRate" name="nominalInterestRate" title="" style="width: 70px;" value="{{=$ctx.decimal(interestRatePerPeriod, 4)}}" />
<select id="selectedInterestFrequencyOption" name="selectedInterestFrequencyOption" title="" style="width: 115px;"> <select id="selectedInterestFrequencyOption" name="selectedInterestFrequencyOption" title="" style="width: 139px;">
{{#each interestFrequencyOptions}} {{#each interestFrequencyOptions}}
{{#if $ctx.number($parent.parent.data.interestRatePeriod)===$ctx.number(id)}} {{#if $ctx.number($parent.parent.data.interestRatePeriod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option> <option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
{{#else}} {{#else}}
<option value="{{=$ctx.number(id)}}">{{=value}}</option> <option value="{{=$ctx.number(id)}}">{{=value}}</option>
{{/if}} {{/if}}
{{/each}}
</select>
</td>
</tr>
<tr>
<td><spring:message code="form.label.loan.product.amortization"/></td>
<td>
<select id="selectedAmortizationMethodOption" name="selectedAmortizationMethodOption" title="" style="width: 220px;">
{{#each possibleAmortizationOptions}}
{{#if $ctx.number($parent.parent.data.amortizationMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
{{#else}}
<option value="{{=$ctx.number(id)}}">{{=value}}</option>
{{/if}}
{{/each}} {{/each}}
</select> </select>
</td> </td>
@@ -125,7 +119,7 @@
<tr> <tr>
<td><spring:message code="form.label.loan.product.interest.method"/></td> <td><spring:message code="form.label.loan.product.interest.method"/></td>
<td> <td>
<select id="selectedInterestMethodOption" name="selectedInterestMethodOption" title="" style="width: 180px;"> <select id="selectedInterestMethodOption" name="selectedInterestMethodOption" title="" style="width: 220px;">
{{#each possibleInterestOptions}} {{#each possibleInterestOptions}}
{{#if $ctx.number($parent.parent.data.interestMethod)===$ctx.number(id)}} {{#if $ctx.number($parent.parent.data.interestMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option> <option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -136,6 +130,26 @@
</select> </select>
</td> </td>
</tr> </tr>
<tr>
<td><spring:message code="form.label.loan.product.interest.rate.calcutated.in.period"/></td>
<td>
<select id="interestRateCalculatedInPeriod" name="interestRateCalculatedInPeriod" title="" style="width: 220px;">
{{#each possibleInterestRateCalculatedInPeriodOptions}}
{{#if $ctx.number($parent.parent.data.interestRateCalculatedInPeriod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
{{#else}}
<option value="{{=$ctx.number(id)}}">{{=value}}</option>
{{/if}}
{{/each}}
</select>
</td>
</tr>
<tr>
<td><spring:message code="form.label.loan.product.arrears.tolerance"/></td>
<td>
<input id="inArrearsTolerance" name="inArrearsTolerance" title="" style="width: 215px;" value="{{=$ctx.money(inArrearsTolerance)}}" />
</td>
</tr>
</table> </table>
</td> </td>
</tr> </tr>
@@ -201,20 +201,6 @@ $(document).ready(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#nominalInterestRate').change(function() {
calculateAnnualPercentageRate();
calculateLoanSchedule();
});
$('#selectedInterestFrequencyOption').change(function() {
calculateAnnualPercentageRate();
calculateLoanSchedule();
});
$('#selectedInterestMethodOption').change(function() {
calculateLoanSchedule();
});
$('#repaidEvery').change(function() { $('#repaidEvery').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
@@ -227,10 +213,6 @@ $(document).ready(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#selectedAmortizationMethodOption').change(function() {
calculateLoanSchedule();
});
$('#expectedDisbursementDate').change(function() { $('#expectedDisbursementDate').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
@@ -239,6 +221,28 @@ $(document).ready(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#nominalInterestRate').change(function() {
calculateAnnualPercentageRate();
calculateLoanSchedule();
});
$('#selectedInterestFrequencyOption').change(function() {
calculateAnnualPercentageRate();
calculateLoanSchedule();
});
$('#selectedAmortizationMethodOption').change(function() {
calculateLoanSchedule();
});
$('#selectedInterestMethodOption').change(function() {
calculateLoanSchedule();
});
$('#interestRateCalculatedInPeriod').change(function() {
calculateLoanSchedule();
});
$('#interestCalculatedFromDate').change(function() { $('#interestCalculatedFromDate').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
@@ -128,27 +128,6 @@
<input id="numberOfRepayments" name="numberOfRepayments" title="" type="text" value="{{=$ctx.number(selectedProduct.numberOfRepayments)}}" style="width: 50px;" /> <input id="numberOfRepayments" name="numberOfRepayments" title="" type="text" value="{{=$ctx.number(selectedProduct.numberOfRepayments)}}" style="width: 50px;" />
</td> </td>
</tr> </tr>
<tr>
<td><spring:message code="form.label.loan.product.amortization"/></td>
<td>
<select name="selectedAmortizationMethodOption" id="selectedAmortizationMethodOption" title="" style="width: 178px;">
{{#each selectedProduct.possibleAmortizationOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.amortizationMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
{{#else}}
<option value="{{=$ctx.number(id)}}">{{=value}}</option>
{{/if}}
{{/each}}
</select>
</td>
</tr>
<tr>
<td><spring:message code="form.label.loan.product.arrears.tolerance"/></td>
<td>
<input id="inArrearsTolerance" name="inArrearsTolerance" title="" type="text" value="{{=$ctx.money(selectedProduct.inArrearsTolerance)}}" style="width: 125px;" />
<input id="inArrearsTolerance.currencyCode" name="inArrearsTolerance.currencyCode" title="" type="text" value="{{=selectedProduct.inArrearsTolerance.displaySymbol}}" style="width: 40px;" disabled="disabled" />
</td>
</tr>
<tr> <tr>
<td><spring:message code="form.label.loan.expected.disbursement.date.on"/></td> <td><spring:message code="form.label.loan.expected.disbursement.date.on"/></td>
<td> <td>
@@ -188,6 +167,20 @@
<input id="interestRatePerYear" name="interestRatePerYear" title="" type="text" style="width: 60px;" disabled="disabled" /> <input id="interestRatePerYear" name="interestRatePerYear" title="" type="text" style="width: 60px;" disabled="disabled" />
</td> </td>
</tr> </tr>
<tr>
<td><spring:message code="form.label.loan.product.amortization"/></td>
<td>
<select name="selectedAmortizationMethodOption" id="selectedAmortizationMethodOption" title="" style="width: 178px;">
{{#each selectedProduct.possibleAmortizationOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.amortizationMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
{{#else}}
<option value="{{=$ctx.number(id)}}">{{=value}}</option>
{{/if}}
{{/each}}
</select>
</td>
</tr>
<tr> <tr>
<td><spring:message code="form.label.loan.product.interest.method"/></td> <td><spring:message code="form.label.loan.product.interest.method"/></td>
<td> <td>
@@ -202,12 +195,33 @@
</select> </select>
</td> </td>
</tr> </tr>
<tr>
<td><spring:message code="form.label.loan.product.interest.rate.calcutated.in.period"/></td>
<td>
<select id="interestRateCalculatedInPeriod" name="interestRateCalculatedInPeriod" title="" style="width: 220px;">
{{#each selectedProduct.possibleInterestRateCalculatedInPeriodOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.interestRateCalculatedInPeriod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
{{#else}}
<option value="{{=$ctx.number(id)}}">{{=value}}</option>
{{/if}}
{{/each}}
</select>
</td>
</tr>
<tr> <tr>
<td><spring:message code="form.label.loan.interest.charged.from"/></td> <td><spring:message code="form.label.loan.interest.charged.from"/></td>
<td> <td>
<input id="interestCalculatedFromDate" name="interestCalculatedFromDate" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(interestCalculatedFromDate)}}" style="width:172px;"/> <input id="interestCalculatedFromDate" name="interestCalculatedFromDate" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(interestCalculatedFromDate)}}" style="width:172px;"/>
</td> </td>
</tr> </tr>
<tr>
<td><spring:message code="form.label.loan.product.arrears.tolerance"/></td>
<td>
<input id="inArrearsTolerance" name="inArrearsTolerance" title="" type="text" value="{{=$ctx.money(selectedProduct.inArrearsTolerance)}}" style="width: 125px;" />
<input id="inArrearsTolerance.currencyCode" name="inArrearsTolerance.currencyCode" title="" type="text" value="{{=selectedProduct.inArrearsTolerance.displaySymbol}}" style="width: 40px;" disabled="disabled" />
</td>
</tr>
</table> </table>
</td> </td>
<td> <td>
@@ -12,12 +12,14 @@ import org.mifosng.platform.currency.domain.ApplicationCurrency;
import org.mifosng.platform.currency.domain.ApplicationCurrencyRepository; import org.mifosng.platform.currency.domain.ApplicationCurrencyRepository;
import org.mifosng.platform.currency.domain.MonetaryCurrency; import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.loan.domain.AmortizationMethod; import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod;
import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.Loan; import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanPayoffSummary; import org.mifosng.platform.loan.domain.LoanPayoffSummary;
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail; import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
import org.mifosng.platform.loan.domain.LoanRepository; import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.loanschedule.domain.AprCalculator;
import org.mifosng.platform.loanschedule.domain.DefaultLoanScheduleGeneratorFactory; import org.mifosng.platform.loanschedule.domain.DefaultLoanScheduleGeneratorFactory;
import org.mifosng.platform.loanschedule.domain.LoanScheduleGenerator; import org.mifosng.platform.loanschedule.domain.LoanScheduleGenerator;
import org.mifosng.platform.loanschedule.domain.LoanScheduleGeneratorFactory; import org.mifosng.platform.loanschedule.domain.LoanScheduleGeneratorFactory;
@@ -31,11 +33,13 @@ public class CalculationPlatformServiceImpl implements
private final LoanScheduleGeneratorFactory loanScheduleFactory; private final LoanScheduleGeneratorFactory loanScheduleFactory;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final ApplicationCurrencyRepository applicationCurrencyRepository; private final ApplicationCurrencyRepository applicationCurrencyRepository;
private final AprCalculator aprCalculator;
@Autowired @Autowired
public CalculationPlatformServiceImpl(final LoanRepository loanRepository, final ApplicationCurrencyRepository applicationCurrencyRepository) { public CalculationPlatformServiceImpl(final LoanRepository loanRepository, final ApplicationCurrencyRepository applicationCurrencyRepository, final AprCalculator aprCalculator) {
this.loanRepository = loanRepository; this.loanRepository = loanRepository;
this.applicationCurrencyRepository = applicationCurrencyRepository; this.applicationCurrencyRepository = applicationCurrencyRepository;
this.aprCalculator = aprCalculator;
this.loanScheduleFactory = new DefaultLoanScheduleGeneratorFactory(); this.loanScheduleFactory = new DefaultLoanScheduleGeneratorFactory();
} }
@@ -45,70 +49,46 @@ public class CalculationPlatformServiceImpl implements
CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator(command); CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator(command);
validator.validate(); validator.validate();
// assemble 'loan data' into 'domain' object [LoanProductRelatedDetail]
final BigDecimal principalAmount = BigDecimal.valueOf(command.getPrincipal().doubleValue());
final BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(command.getInterestRatePerPeriod().doubleValue());
final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
final Integer repayEvery = command.getRepaymentEvery();
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency());
final Integer defaultNumberOfInstallments = command.getNumberOfRepayments();
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
final boolean flexibleRepaymentSchedule = command.isFlexibleRepaymentSchedule();
final boolean interestRebateAllowed = command.isInterestRebateAllowed();
final BigDecimal defaultAnnualNominalInterestRate = this.aprCalculator.calculateFrom(interestPeriodFrequencyType, defaultNominalInterestRatePerPeriod);
final MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
// in arrerars tolerance isnt relevant when auto-calculating a loan schedule
final BigDecimal inArrearsTolerance = BigDecimal.ZERO;
LoanProductRelatedDetail loanScheduleInfo = new LoanProductRelatedDetail(currency, principalAmount,
defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate,
interestMethod, interestCalculationPeriodMethod,
repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod,
inArrearsTolerance, flexibleRepaymentSchedule, interestRebateAllowed);
LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod);
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(command.getCurrencyCode()); ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(command.getCurrencyCode());
CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(), command.getDigitsAfterDecimal(), CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(), command.getDigitsAfterDecimal(),
applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode()); applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode());
MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal()); return loanScheduleGenerator.generate(loanScheduleInfo, command.getExpectedDisbursementDate(), command.getRepaymentsStartingFromDate(),
command.getInterestCalculatedFromDate(), currencyData);
final BigDecimal principalAmount = BigDecimal.valueOf(command.getPrincipal()
.doubleValue());
final BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(command
.getInterestRatePerPeriod().doubleValue());
final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
final Integer repayEvery = command.getRepaymentEvery();
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType
.fromInt(command.getRepaymentFrequency());
final Integer defaultNumberOfInstallments = command.getNumberOfRepayments();
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
final boolean flexibleRepaymentSchedule = command.isFlexibleRepaymentSchedule();
final boolean interestRebateAllowed = command.isInterestRebateAllowed();
// apr calculator
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO;
switch (interestPeriodFrequencyType) {
case DAYS:
break;
case WEEKS:
defaultAnnualNominalInterestRate = command
.getInterestRatePerPeriod()
.multiply(BigDecimal.valueOf(52));
break;
case MONTHS:
defaultAnnualNominalInterestRate = command
.getInterestRatePerPeriod()
.multiply(BigDecimal.valueOf(12));
break;
case YEARS:
defaultAnnualNominalInterestRate = command
.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(1));
break;
case INVALID:
break;
}
LoanProductRelatedDetail loanScheduleInfo = new LoanProductRelatedDetail(currency, principalAmount,
defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod,
repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, BigDecimal.ZERO, flexibleRepaymentSchedule, interestRebateAllowed);
LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory
.create(interestMethod, amortizationMethod);
return loanScheduleGenerator.generate(loanScheduleInfo, new LocalDate(
command.getExpectedDisbursementDate()), command
.getRepaymentsStartingFromDate(), command.getInterestCalculatedFromDate(), currencyData);
} }
@Override @Override
public LoanPayoffReadModel calculatePayoffOn(final Long loanId, public LoanPayoffReadModel calculatePayoffOn(final Long loanId, final LocalDate payoffDate) {
final LocalDate payoffDate) {
// use jdbc approach to calculating payoff if possible. // TODO - use jdbc approach to calculating payoff if possible.
final Loan loan = this.loanRepository.findOne(loanId); final Loan loan = this.loanRepository.findOne(loanId);
final LoanPayoffSummary payoffSummary = loan.getPayoffSummaryOn(payoffDate); final LoanPayoffSummary payoffSummary = loan.getPayoffSummaryOn(payoffDate);
@@ -37,6 +37,7 @@ import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.exceptions.ClientNotAuthenticatedException; import org.mifosng.platform.exceptions.ClientNotAuthenticatedException;
import org.mifosng.platform.loan.domain.AmortizationMethod; import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine; import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine;
import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod;
import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.Loan; import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanBuilder; import org.mifosng.platform.loan.domain.LoanBuilder;
@@ -167,6 +168,7 @@ public class ImportPlatformServiceImpl implements ImportPlatformService {
} }
final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod()); final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
final Integer repayEvery = command.getRepaymentEvery(); final Integer repayEvery = command.getRepaymentEvery();
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType
@@ -177,7 +179,7 @@ public class ImportPlatformServiceImpl implements ImportPlatformService {
final boolean interestRebateAllowed = command.isInterestRebateAllowed(); final boolean interestRebateAllowed = command.isInterestRebateAllowed();
LoanProductRelatedDetail loanRepaymentScheduleDetail = new LoanProductRelatedDetail(currency, command.getPrincipal(), LoanProductRelatedDetail loanRepaymentScheduleDetail = new LoanProductRelatedDetail(currency, command.getPrincipal(),
defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, command.getInArrearsToleranceAmount(), flexibleRepaymentSchedule, interestRebateAllowed); repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, command.getInArrearsToleranceAmount(), flexibleRepaymentSchedule, interestRebateAllowed);
LoanSchedule loanSchedule = command.getLoanSchedule(); LoanSchedule loanSchedule = command.getLoanSchedule();
@@ -460,11 +462,12 @@ public class ImportPlatformServiceImpl implements ImportPlatformService {
Number interestRatePerPeriod = interestRatePerYear; Number interestRatePerPeriod = interestRatePerYear;
Integer interestRatePeriodFrequency = PeriodFrequencyType.YEARS.getValue(); Integer interestRatePeriodFrequency = PeriodFrequencyType.YEARS.getValue();
Integer interestMethod = matchingProduct.getInterestMethod().getValue(); Integer interestMethod = matchingProduct.getInterestMethod().getValue();
Integer interestCalculationPeriodMethod = InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD.getValue();
CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal,
interestRatePerPeriod, interestRatePerPeriod,
interestRatePeriodFrequency, interestRatePeriodFrequency,
interestMethod, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentEvery,
repaymentFrequency, numberOfRepayments, amortizationMethod, flexibleRepaymentSchedule, repaymentFrequency, numberOfRepayments, amortizationMethod, flexibleRepaymentSchedule,
matchingProduct.isInterestRebateAllowed(), expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate); matchingProduct.isInterestRebateAllowed(), expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
@@ -474,7 +477,7 @@ public class ImportPlatformServiceImpl implements ImportPlatformService {
SubmitLoanApplicationCommand parsedNewLoanDetails = new SubmitLoanApplicationCommand(matchingClient.getId(), matchingProduct.getId(), submittedOnDate, noNoteComment, SubmitLoanApplicationCommand parsedNewLoanDetails = new SubmitLoanApplicationCommand(matchingClient.getId(), matchingProduct.getId(), submittedOnDate, noNoteComment,
expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate, loanSchedule, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate, loanSchedule,
currencyCode, digitsAfterDecimal, principal, currencyCode, digitsAfterDecimal, principal,
interestRatePerPeriod, interestRatePeriodFrequency, interestMethod, interestRatePerPeriod, interestRatePeriodFrequency, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount.getAmount(), repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount.getAmount(),
flexibleRepaymentSchedule, matchingProduct.isInterestRebateAllowed()); flexibleRepaymentSchedule, matchingProduct.isInterestRebateAllowed());
@@ -54,6 +54,8 @@ public interface ReadPlatformService {
List<EnumOptionReadModel> retrieveLoanInterestMethodOptions(); List<EnumOptionReadModel> retrieveLoanInterestMethodOptions();
List<EnumOptionReadModel> retrieveLoanInterestRateCalculatedInPeriodOptions();
List<EnumOptionReadModel> retrieveRepaymentFrequencyOptions(); List<EnumOptionReadModel> retrieveRepaymentFrequencyOptions();
List<EnumOptionReadModel> retrieveInterestFrequencyOptions(); List<EnumOptionReadModel> retrieveInterestFrequencyOptions();
@@ -749,7 +749,7 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
return "lp.id as id, lp.name as name, lp.description as description, lp.flexible_repayment_schedule as isFlexible, lp.interest_rebate as isInterestRebateAllowed, " return "lp.id as id, lp.name as name, lp.description as description, lp.flexible_repayment_schedule as isFlexible, lp.interest_rebate as isInterestRebateAllowed, "
+ "lp.principal_amount as principal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, " + "lp.principal_amount as principal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, "
+ "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, " + "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, "
+ "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, " + "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod,"
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, " + "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, "
+ "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, " + "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, "
+ "lp.created_date as createdon, lp.lastmodified_date as modifiedon " + "lp.created_date as createdon, lp.lastmodified_date as modifiedon "
@@ -786,6 +786,7 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
BigDecimal annualInterestRate = rs BigDecimal annualInterestRate = rs
.getBigDecimal("annualInterestRate"); .getBigDecimal("annualInterestRate");
int interestMethod = rs.getInt("interestMethod"); int interestMethod = rs.getInt("interestMethod");
int interestCalculationInPeriodMethod = rs.getInt("interestCalculationInPeriodMethod");
int repaidEvery = rs.getInt("repaidEvery"); int repaidEvery = rs.getInt("repaidEvery");
int repaymentFrequency = rs.getInt("repaymentPeriodFrequency"); int repaymentFrequency = rs.getInt("repaymentPeriodFrequency");
@@ -798,7 +799,8 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
return new LoanProductData(id, name, description, isFlexible, return new LoanProductData(id, name, description, isFlexible,
isInterestRebateAllowed, principalMoney, isInterestRebateAllowed, principalMoney,
interestRatePerPeriod, interestRatePeriod, interestRatePerPeriod, interestRatePeriod,
annualInterestRate, interestMethod, repaidEvery, annualInterestRate, interestMethod, interestCalculationInPeriodMethod,
repaidEvery,
repaymentFrequency, numberOfRepayments, amortizationMethod, repaymentFrequency, numberOfRepayments, amortizationMethod,
toleranceMoney, createdOn, lastModifedOn); toleranceMoney, createdOn, lastModifedOn);
} }
@@ -818,7 +820,8 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
@Override @Override
public LoanProductData retrieveLoanProduct(final Long loanProductId) { public LoanProductData retrieveLoanProduct(final Long loanProductId) {
List<CurrencyData> allowedCurrencies = retrieveAllowedCurrencies(); // TODO - switch back to retrieve all allowed organisation currencies
List<CurrencyData> allowedCurrencies = retrieveAllPlatformCurrencies();
LoanProductMapper rm = new LoanProductMapper(allowedCurrencies); LoanProductMapper rm = new LoanProductMapper(allowedCurrencies);
String sql = "select " + rm.loanProductSchema() + " where lp.id = ?"; String sql = "select " + rm.loanProductSchema() + " where lp.id = ?";
@@ -838,12 +841,14 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
List<EnumOptionReadModel> possibleAmortizationOptions = retrieveLoanAmortizationMethodOptions(); List<EnumOptionReadModel> possibleAmortizationOptions = retrieveLoanAmortizationMethodOptions();
List<EnumOptionReadModel> possibleInterestOptions = retrieveLoanInterestMethodOptions(); List<EnumOptionReadModel> possibleInterestOptions = retrieveLoanInterestMethodOptions();
List<EnumOptionReadModel> possibleInterestRateCalculatedInPeriodOptions = retrieveLoanInterestRateCalculatedInPeriodOptions();
List<EnumOptionReadModel> repaymentFrequencyOptions = retrieveRepaymentFrequencyOptions(); List<EnumOptionReadModel> repaymentFrequencyOptions = retrieveRepaymentFrequencyOptions();
List<EnumOptionReadModel> interestFrequencyOptions = retrieveInterestFrequencyOptions(); List<EnumOptionReadModel> interestFrequencyOptions = retrieveInterestFrequencyOptions();
productData.setPossibleCurrencies(possibleCurrencies); productData.setPossibleCurrencies(possibleCurrencies);
productData.setPossibleAmortizationOptions(possibleAmortizationOptions); productData.setPossibleAmortizationOptions(possibleAmortizationOptions);
productData.setPossibleInterestOptions(possibleInterestOptions); productData.setPossibleInterestOptions(possibleInterestOptions);
productData.setPossibleInterestRateCalculatedInPeriodOptions(possibleInterestRateCalculatedInPeriodOptions);
productData.setRepaymentFrequencyOptions(repaymentFrequencyOptions); productData.setRepaymentFrequencyOptions(repaymentFrequencyOptions);
productData.setInterestFrequencyOptions(interestFrequencyOptions); productData.setInterestFrequencyOptions(interestFrequencyOptions);
} }
@@ -866,6 +871,7 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
productData.setInterestMethod(Integer.valueOf(0)); productData.setInterestMethod(Integer.valueOf(0));
productData.setRepaymentPeriodFrequency(2); productData.setRepaymentPeriodFrequency(2);
productData.setInterestRatePeriod(2); productData.setInterestRatePeriod(2);
productData.setInterestRateCalculatedInPeriod(1);
productData.setRepaidEvery(1); productData.setRepaidEvery(1);
productData.setNumberOfRepayments(0); productData.setNumberOfRepayments(0);
@@ -943,6 +949,17 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
return allowedRepaymentScheduleCalculationMethods; return allowedRepaymentScheduleCalculationMethods;
} }
@Override
public List<EnumOptionReadModel> retrieveLoanInterestRateCalculatedInPeriodOptions() {
EnumOptionReadModel option1 = new EnumOptionReadModel("Daily", Long.valueOf(0));
EnumOptionReadModel option2 = new EnumOptionReadModel("Same as repayment period", Long.valueOf(1));
List<EnumOptionReadModel> allowedOptions = Arrays.asList(option1,option2);
return allowedOptions;
}
@Override @Override
public List<EnumOptionReadModel> retrieveRepaymentFrequencyOptions() { public List<EnumOptionReadModel> retrieveRepaymentFrequencyOptions() {
EnumOptionReadModel frequency1 = new EnumOptionReadModel("Days", EnumOptionReadModel frequency1 = new EnumOptionReadModel("Days",
@@ -958,14 +975,12 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
@Override @Override
public List<EnumOptionReadModel> retrieveInterestFrequencyOptions() { public List<EnumOptionReadModel> retrieveInterestFrequencyOptions() {
EnumOptionReadModel perWeek = new EnumOptionReadModel("Per week", // support for monthly and annual percentage rate (MPR) and (APR)
PeriodFrequencyType.WEEKS.getValue().longValue());
EnumOptionReadModel perMonth = new EnumOptionReadModel("Per month", EnumOptionReadModel perMonth = new EnumOptionReadModel("Per month",
PeriodFrequencyType.MONTHS.getValue().longValue()); PeriodFrequencyType.MONTHS.getValue().longValue());
EnumOptionReadModel perYear = new EnumOptionReadModel("Per year", EnumOptionReadModel perYear = new EnumOptionReadModel("Per year",
PeriodFrequencyType.YEARS.getValue().longValue()); PeriodFrequencyType.YEARS.getValue().longValue());
List<EnumOptionReadModel> repaymentFrequencyOptions = Arrays.asList( List<EnumOptionReadModel> repaymentFrequencyOptions = Arrays.asList(perMonth, perYear);
perWeek, perMonth, perYear);
return repaymentFrequencyOptions; return repaymentFrequencyOptions;
} }
@@ -40,7 +40,8 @@ public class SubmitLoanApplicationCommandValidator {
command.getCurrencyCode(), command.getDigitsAfterDecimal(), command.getCurrencyCode(), command.getDigitsAfterDecimal(),
command.getPrincipal(), command.getInterestRatePerPeriod(), command.getPrincipal(), command.getInterestRatePerPeriod(),
command.getInterestRateFrequencyMethod(), command.getInterestRateFrequencyMethod(),
command.getInterestMethod(), command.getRepaymentEvery(), command.getInterestMethod(), command.getInterestCalculationPeriodMethod(),
command.getRepaymentEvery(),
command.getRepaymentFrequency(), command.getRepaymentFrequency(),
command.getNumberOfRepayments(), command.getNumberOfRepayments(),
command.getAmortizationMethod(), command.getAmortizationMethod(),
@@ -54,6 +54,7 @@ import org.mifosng.platform.infrastructure.PlatformUser;
import org.mifosng.platform.infrastructure.UsernameAlreadyExistsException; import org.mifosng.platform.infrastructure.UsernameAlreadyExistsException;
import org.mifosng.platform.loan.domain.AmortizationMethod; import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine; import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine;
import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod;
import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.Loan; import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanBuilder; import org.mifosng.platform.loan.domain.LoanBuilder;
@@ -447,8 +448,8 @@ public class WritePlatformServiceJpaRepositoryImpl implements
validator.validateForCreate(command); validator.validateForCreate(command);
// assemble LoanProduct from data // assemble LoanProduct from data
InterestMethod interestMethod = InterestMethod InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
.fromInt(command.getInterestMethod()); InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod()); AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
@@ -480,7 +481,7 @@ public class WritePlatformServiceJpaRepositoryImpl implements
LoanProduct loanproduct = new LoanProduct(currentUser.getOrganisation(), command.getName(), command.getDescription(), LoanProduct loanproduct = new LoanProduct(currentUser.getOrganisation(), command.getName(), command.getDescription(),
currency, command.getPrincipal(), currency, command.getPrincipal(),
command.getInterestRatePerPeriod(), interestFrequencyType, annualInterestRate, interestMethod, command.getInterestRatePerPeriod(), interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod,
command.getRepaymentEvery(), repaymentFrequencyType, command.getNumberOfRepayments(), amortizationMethod, command.getInArrearsToleranceAmount(), command.getRepaymentEvery(), repaymentFrequencyType, command.getNumberOfRepayments(), amortizationMethod, command.getInArrearsToleranceAmount(),
command.isFlexibleRepaymentSchedule(), command.isInterestRebateAllowed()); command.isFlexibleRepaymentSchedule(), command.isInterestRebateAllowed());
@@ -652,7 +653,8 @@ public class WritePlatformServiceJpaRepositoryImpl implements
break; break;
} }
final InterestMethod interestMethod = InterestMethod.DECLINING_BALANCE; final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
final Integer repayEvery = command.getRepaymentEvery(); final Integer repayEvery = command.getRepaymentEvery();
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType
@@ -663,7 +665,8 @@ public class WritePlatformServiceJpaRepositoryImpl implements
final boolean interestRebateAllowed = command.isInterestRebateAllowed(); final boolean interestRebateAllowed = command.isInterestRebateAllowed();
LoanProductRelatedDetail loanRepaymentScheduleDetail = new LoanProductRelatedDetail(currency, LoanProductRelatedDetail loanRepaymentScheduleDetail = new LoanProductRelatedDetail(currency,
command.getPrincipal(), defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, command.getPrincipal(), defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate,
interestMethod, interestCalculationPeriodMethod,
repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, command.getInArrearsToleranceAmount(), repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, command.getInArrearsToleranceAmount(),
flexibleRepaymentSchedule, interestRebateAllowed); flexibleRepaymentSchedule, interestRebateAllowed);
@@ -890,41 +893,32 @@ public class WritePlatformServiceJpaRepositoryImpl implements
if (loan.isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) { if (loan.isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) {
LocalDate repaymentsStartingFromDate = loan LocalDate repaymentsStartingFromDate = loan.getExpectedFirstRepaymentOnDate();
.getExpectedFirstRepaymentOnDate();
LocalDate interestCalculatedFromDate = loan.getInterestCalculatedFromDate(); LocalDate interestCalculatedFromDate = loan.getInterestCalculatedFromDate();
Number principalAsDecimal = loan.getLoanRepaymentScheduleDetail() Number principalAsDecimal = loan.getLoanRepaymentScheduleDetail().getPrincipal().getAmount();
.getPrincipal().getAmount(); String currencyCode = loan.getLoanRepaymentScheduleDetail().getPrincipal().getCurrencyCode();
String currencyCode = loan.getLoanRepaymentScheduleDetail() int currencyDigits = loan.getLoanRepaymentScheduleDetail().getPrincipal().getCurrencyDigitsAfterDecimal();
.getPrincipal().getCurrencyCode();
int currencyDigits = loan.getLoanRepaymentScheduleDetail()
.getPrincipal().getCurrencyDigitsAfterDecimal();
Number interestRatePerYear = loan.getLoanRepaymentScheduleDetail() Number interestRatePerYear = loan.getLoanRepaymentScheduleDetail().getAnnualNominalInterestRate();
.getAnnualNominalInterestRate(); Integer numberOfInstallments = loan.getLoanRepaymentScheduleDetail().getNumberOfRepayments();
Integer numberOfInstallments = loan
.getLoanRepaymentScheduleDetail().getNumberOfRepayments();
Integer repaidEvery = loan.getLoanRepaymentScheduleDetail() Integer repaidEvery = loan.getLoanRepaymentScheduleDetail().getRepayEvery();
.getRepayEvery(); Integer selectedRepaymentFrequency = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType().getValue();
Integer selectedRepaymentFrequency = loan Integer selectedRepaymentSchedule = loan.getLoanRepaymentScheduleDetail().getAmortizationMethod().getValue();
.getLoanRepaymentScheduleDetail() boolean flexibleRepaymentSchedule = loan.isFlexibleRepaymentSchedule();
.getRepaymentPeriodFrequencyType().getValue();
Integer selectedRepaymentSchedule = loan
.getLoanRepaymentScheduleDetail()
.getAmortizationMethod().getValue();
boolean flexibleRepaymentSchedule = loan
.isFlexibleRepaymentSchedule();
// use annual percentage rate to re-calculate loan schedule for late disbursement
Number interestRatePerPeriod = interestRatePerYear; Number interestRatePerPeriod = interestRatePerYear;
Integer interestRateFrequencyMethod = PeriodFrequencyType.YEARS.getValue(); Integer interestRateFrequencyMethod = PeriodFrequencyType.YEARS.getValue();
Integer interestMethod = InterestMethod.DECLINING_BALANCE.getValue();
boolean interestRebateAllowed = false; Integer interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod().getValue();
Integer interestCalculationInPeriod = loan.getLoanRepaymentScheduleDetail().getInterestCalculationPeriodMethod().getValue();
boolean interestRebateAllowed = loan.getLoanRepaymentScheduleDetail().isInterestRebateAllowed();
CalculateLoanScheduleCommand calculateCommand = new CalculateLoanScheduleCommand(currencyCode, currencyDigits, principalAsDecimal, CalculateLoanScheduleCommand calculateCommand = new CalculateLoanScheduleCommand(currencyCode, currencyDigits, principalAsDecimal,
interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, repaidEvery, selectedRepaymentFrequency, numberOfInstallments, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, interestCalculationInPeriod,
repaidEvery, selectedRepaymentFrequency, numberOfInstallments,
selectedRepaymentSchedule, flexibleRepaymentSchedule, interestRebateAllowed, actualDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate); selectedRepaymentSchedule, flexibleRepaymentSchedule, interestRebateAllowed, actualDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
LoanSchedule loanSchedule = this.calculationPlatformService.calculateLoanSchedule(calculateCommand); LoanSchedule loanSchedule = this.calculationPlatformService.calculateLoanSchedule(calculateCommand);
@@ -951,8 +945,7 @@ public class WritePlatformServiceJpaRepositoryImpl implements
interest.getAmount()); interest.getAmount());
modifiedLoanRepaymentSchedule.add(installment); modifiedLoanRepaymentSchedule.add(installment);
} }
loan.disburseWithModifiedRepaymentSchedule(disbursedOn, comment, loan.disburseWithModifiedRepaymentSchedule(disbursedOn, comment, modifiedLoanRepaymentSchedule, defaultLoanLifecycleStateMachine());
modifiedLoanRepaymentSchedule, defaultLoanLifecycleStateMachine());
} else { } else {
loan.disburse(disbursedOn, defaultLoanLifecycleStateMachine()); loan.disburse(disbursedOn, defaultLoanLifecycleStateMachine());
} }
@@ -0,0 +1,32 @@
package org.mifosng.platform.loan.domain;
public enum InterestCalculationPeriodMethod {
DAILY(0), SAME_AS_REPAYMENT_PERIOD(1), INVALID(2);
private final Integer value;
private InterestCalculationPeriodMethod(final Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
public static InterestCalculationPeriodMethod fromInt(final Integer selectedMethod) {
InterestCalculationPeriodMethod repaymentMethod = null;
switch (selectedMethod) {
case 0:
repaymentMethod = InterestCalculationPeriodMethod.DAILY;
break;
case 1:
repaymentMethod = InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD;
break;
default:
repaymentMethod = InterestCalculationPeriodMethod.INVALID;
break;
}
return repaymentMethod;
}
}
@@ -50,7 +50,8 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
} }
public LoanProduct(final Organisation organisation, final String name, final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal, public LoanProduct(final Organisation organisation, final String name, final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal,
final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultAnnualNominalInterestRate,
final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
final Integer repayEvery, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments, final AmortizationMethod amortizationMethod, final Integer repayEvery, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments, final AmortizationMethod amortizationMethod,
final BigDecimal inArrearsTolerance, final BigDecimal inArrearsTolerance,
final boolean flexibleRepaymentSchedule, final boolean flexibleRepaymentSchedule,
@@ -64,7 +65,8 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
} }
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency,
defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate,
interestMethod, interestCalculationPeriodMethod,
repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, inArrearsTolerance, flexibleRepaymentSchedule, interestRebateAllowed); repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, inArrearsTolerance, flexibleRepaymentSchedule, interestRebateAllowed);
} }
@@ -40,6 +40,10 @@ public class LoanProductRelatedDetail implements
@Column(name = "interest_method_enum", nullable = false) @Column(name = "interest_method_enum", nullable = false)
private InterestMethod interestMethod; private InterestMethod interestMethod;
@Enumerated(EnumType.ORDINAL)
@Column(name = "interest_calculated_in_period_enum", nullable = false)
private InterestCalculationPeriodMethod interestCalculationPeriodMethod;
@Column(name = "repay_every", nullable = false) @Column(name = "repay_every", nullable = false)
private Integer repayEvery; private Integer repayEvery;
@@ -85,7 +89,9 @@ public class LoanProductRelatedDetail implements
final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultNominalInterestRatePerPeriod,
final PeriodFrequencyType interestPeriodFrequencyType, final PeriodFrequencyType interestPeriodFrequencyType,
final BigDecimal defaultAnnualNominalInterestRate, final BigDecimal defaultAnnualNominalInterestRate,
final InterestMethod interestMethod, final Integer repayEvery, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
final Integer repayEvery,
final PeriodFrequencyType repaymentFrequencyType, final PeriodFrequencyType repaymentFrequencyType,
final Integer defaultNumberOfRepayments, final Integer defaultNumberOfRepayments,
final AmortizationMethod amortizationMethod, final AmortizationMethod amortizationMethod,
@@ -98,6 +104,7 @@ public class LoanProductRelatedDetail implements
this.interestPeriodFrequencyType = interestPeriodFrequencyType; this.interestPeriodFrequencyType = interestPeriodFrequencyType;
this.annualNominalInterestRate = defaultAnnualNominalInterestRate; this.annualNominalInterestRate = defaultAnnualNominalInterestRate;
this.interestMethod = interestMethod; this.interestMethod = interestMethod;
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
this.repayEvery = repayEvery; this.repayEvery = repayEvery;
this.repaymentPeriodFrequencyType = repaymentFrequencyType; this.repaymentPeriodFrequencyType = repaymentFrequencyType;
this.numberOfRepayments = defaultNumberOfRepayments; this.numberOfRepayments = defaultNumberOfRepayments;
@@ -135,6 +142,10 @@ public class LoanProductRelatedDetail implements
return interestMethod; return interestMethod;
} }
public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
return interestCalculationPeriodMethod;
}
@Override @Override
public Integer getRepayEvery() { public Integer getRepayEvery() {
return repayEvery; return repayEvery;
@@ -175,5 +186,6 @@ public class LoanProductRelatedDetail implements
this.nominalInterestRatePerPeriod = command.getInterestRatePerPeriod(); this.nominalInterestRatePerPeriod = command.getInterestRatePerPeriod();
this.interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod()); this.interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
this.interestMethod = InterestMethod.fromInt(command.getInterestMethod()); this.interestMethod = InterestMethod.fromInt(command.getInterestMethod());
this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
} }
} }
@@ -0,0 +1,32 @@
package org.mifosng.platform.loanschedule.domain;
import java.math.BigDecimal;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.springframework.stereotype.Component;
@Component
public class AprCalculator {
public BigDecimal calculateFrom(PeriodFrequencyType interestPeriodFrequencyType, BigDecimal interestRatePerPeriod) {
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO;
switch (interestPeriodFrequencyType) {
case DAYS:
break;
case WEEKS:
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(52));
break;
case MONTHS:
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(12));
break;
case YEARS:
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(1));
break;
case INVALID:
break;
}
return defaultAnnualNominalInterestRate;
}
}
@@ -1,107 +0,0 @@
package org.mifosng.platform.loanschedule.domain;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosng.data.CurrencyData;
import org.mifosng.data.LoanSchedule;
import org.mifosng.data.MoneyData;
import org.mifosng.data.ScheduledLoanInstallment;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.exceptions.NoAuthorizationException;
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
public class DecliningBalanceLoanScheduleGenerator implements
LoanScheduleGenerator {
private final ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
@Override
public LoanSchedule generate(
final LoanProductRelatedDetail loanScheduleInfo,
final LocalDate disbursementDate, final LocalDate firstRepaymentDate,
LocalDate interestCalculatedFrom, CurrencyData currencyData) {
if (firstRepaymentDate != null
&& disbursementDate.isAfter(firstRepaymentDate)) {
throw new NoAuthorizationException(
"cannot have disbursement date after first repayment date.");
}
List<ScheduledLoanInstallment> scheduledLoanInstallments = new ArrayList<ScheduledLoanInstallment>();
List<LocalDate> scheduledDates = this.scheduledDateGenerator.generate(
loanScheduleInfo, disbursementDate, firstRepaymentDate);
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
Money principalPerInstallment = loanScheduleInfo.getPrincipal()
.dividedBy(loanScheduleInfo.getNumberOfRepayments(),
RoundingMode.HALF_EVEN);
BigDecimal paymentPeriodsInYear = BigDecimal
.valueOf(this.paymentPeriodsInOneYearCalculator
.calculate(loanScheduleInfo.getRepaymentPeriodFrequencyType()));
BigDecimal periodicInterestRate = loanScheduleInfo
.getAnnualNominalInterestRate()
.divide(paymentPeriodsInYear, mc)
.divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc)
.multiply(BigDecimal.valueOf(loanScheduleInfo.getRepayEvery()));
Money outstandingBalance = loanScheduleInfo.getPrincipal();
Money totalPrincipal = Money.zero(outstandingBalance.getCurrency());
LocalDate startDate = disbursementDate;
int installmentNumber = 1;
for (LocalDate scheduledDueDate : scheduledDates) {
totalPrincipal = totalPrincipal.plus(principalPerInstallment);
Money interestPerInstallment = outstandingBalance
.multiplyRetainScale(periodicInterestRate,
RoundingMode.HALF_EVEN);
if (installmentNumber == loanScheduleInfo.getNumberOfRepayments()) {
Money difference = totalPrincipal.minus(loanScheduleInfo
.getPrincipal());
if (difference.isLessThanZero()) {
principalPerInstallment = principalPerInstallment
.plus(difference.abs());
} else if (difference.isGreaterThanZero()) {
principalPerInstallment = principalPerInstallment
.minus(difference.abs());
}
}
Money totalInstallmentDue = principalPerInstallment.plus(interestPerInstallment);
outstandingBalance = outstandingBalance
.minus(principalPerInstallment);
MoneyData principalPerInstallmentValue = MoneyData.of(currencyData, principalPerInstallment.getAmount());
MoneyData interestPerInstallmentValue = MoneyData.of(currencyData, interestPerInstallment.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);
scheduledLoanInstallments.add(installment);
startDate = scheduledDueDate;
installmentNumber++;
}
return new LoanSchedule(scheduledLoanInstallments);
}
}
@@ -1,11 +1,10 @@
package org.mifosng.platform.loanschedule.domain; package org.mifosng.platform.loanschedule.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.joda.time.Days;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosng.data.CurrencyData; import org.mifosng.data.CurrencyData;
import org.mifosng.data.LoanSchedule; import org.mifosng.data.LoanSchedule;
@@ -13,13 +12,16 @@ import org.mifosng.data.MoneyData;
import org.mifosng.data.ScheduledLoanInstallment; import org.mifosng.data.ScheduledLoanInstallment;
import org.mifosng.platform.currency.domain.MonetaryCurrency; import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money; import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail; import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
public class DecliningBalanceEqualInstallmentsLoanScheduleGenerator implements public class DecliningBalanceMethodLoanScheduleGenerator implements
LoanScheduleGenerator { LoanScheduleGenerator {
private final ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator(); private final ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator(); private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
private final PeriodicInterestRateCalculator periodicInterestRateCalculator = new PeriodicInterestRateCalculator();
private final PmtCalculator pmtCalculator = new PmtCalculator();
@Override @Override
public LoanSchedule generate( public LoanSchedule generate(
@@ -30,41 +32,23 @@ public class DecliningBalanceEqualInstallmentsLoanScheduleGenerator implements
List<ScheduledLoanInstallment> scheduledLoanInstallments = new ArrayList<ScheduledLoanInstallment>(); List<ScheduledLoanInstallment> scheduledLoanInstallments = new ArrayList<ScheduledLoanInstallment>();
List<LocalDate> scheduledDates = this.scheduledDateGenerator.generate( // 1. generate valid set of 'due dates' based on some of the 'loan attributes'
loanScheduleInfo, disbursementDate, firstRepaymentDate); List<LocalDate> scheduledDates = this.scheduledDateGenerator.generate(loanScheduleInfo, disbursementDate, firstRepaymentDate);
LocalDate idealDisbursementDateBasedOnFirstRepaymentDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(loanScheduleInfo, scheduledDates); // 2. determine the 'periodic' interest rate based on the 'repayment periods' so we can use
final BigDecimal periodInterestRateForRepaymentPeriod = this.periodicInterestRateCalculator.calculateFrom(loanScheduleInfo);
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
BigDecimal paymentPeriodsInYear = BigDecimal
.valueOf(this.paymentPeriodsInOneYearCalculator.calculate(loanScheduleInfo.getRepaymentPeriodFrequencyType()));
BigDecimal periodicInterestRate = loanScheduleInfo
.getAnnualNominalInterestRate()
.divide(paymentPeriodsInYear, mc)
.divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc)
.multiply(BigDecimal.valueOf(loanScheduleInfo.getRepayEvery()));
double interestRateFraction = periodicInterestRate.doubleValue();
double futureValue = 0;
double numberOfPeriods = loanScheduleInfo.getNumberOfRepayments().doubleValue();
double principal = loanScheduleInfo.getPrincipal().getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue();
double paymentPerInstallment = pmt(interestRateFraction, numberOfPeriods, principal, futureValue, false);
double totalRepayment = paymentPerInstallment * numberOfPeriods;
// 3. determine 'total payment' for each repayment based on pmt function (and hence the total due overall)
final MonetaryCurrency monetaryCurrency = loanScheduleInfo.getPrincipal().getCurrency(); final MonetaryCurrency monetaryCurrency = loanScheduleInfo.getPrincipal().getCurrency();
final Money totalDuePerInstallment = this.pmtCalculator.calculatePaymentForOnePeriodFrom(loanScheduleInfo, periodInterestRateForRepaymentPeriod, monetaryCurrency);
Money totalDuePerInstallment = Money.of(monetaryCurrency, BigDecimal.valueOf(paymentPerInstallment)); final Money totalDue = this.pmtCalculator.calculateTotalRepaymentFrom(loanScheduleInfo, periodInterestRateForRepaymentPeriod, monetaryCurrency);
Money totalDue = Money.of(monetaryCurrency, BigDecimal.valueOf(totalRepayment));
Money totalInterestDue = totalDue.minus(loanScheduleInfo.getPrincipal()); Money totalInterestDue = totalDue.minus(loanScheduleInfo.getPrincipal());
Money outstandingBalance = loanScheduleInfo.getPrincipal(); Money outstandingBalance = loanScheduleInfo.getPrincipal();
Money totalPrincipal = Money.zero(monetaryCurrency); Money totalPrincipal = Money.zero(monetaryCurrency);
Money totalInterest = Money.zero(monetaryCurrency); Money totalInterest = Money.zero(monetaryCurrency);
LocalDate idealDisbursementDateBasedOnFirstRepaymentDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(loanScheduleInfo, scheduledDates);
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator.calculateRepaymentPeriodAsAFractionOfDays(loanScheduleInfo.getRepaymentPeriodFrequencyType(), double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator.calculateRepaymentPeriodAsAFractionOfDays(loanScheduleInfo.getRepaymentPeriodFrequencyType(),
loanScheduleInfo.getRepayEvery(), interestCalculatedFrom, scheduledDates, idealDisbursementDateBasedOnFirstRepaymentDate); loanScheduleInfo.getRepayEvery(), interestCalculatedFrom, scheduledDates, idealDisbursementDateBasedOnFirstRepaymentDate);
@@ -72,51 +56,52 @@ public class DecliningBalanceEqualInstallmentsLoanScheduleGenerator implements
int installmentNumber = 1; int installmentNumber = 1;
for (LocalDate scheduledDueDate : scheduledDates) { for (LocalDate scheduledDueDate : scheduledDates) {
Money interestPerInstallment = outstandingBalance.multiplyRetainScale(periodicInterestRate, RoundingMode.HALF_EVEN); // number of days from startDate to this scheduledDate
Money principalPerInstallment = totalDuePerInstallment.minus(interestPerInstallment); int daysInPeriod = Days.daysBetween(startDate.toDateMidnight().toDateTime(), scheduledDueDate.toDateMidnight().toDateTime()).getDays();
Money interestForInstallment = this.periodicInterestRateCalculator.calculateInterestOn(outstandingBalance, periodInterestRateForRepaymentPeriod, daysInPeriod, loanScheduleInfo);
Money principalForInstallment = this.periodicInterestRateCalculator.calculatePrincipalOn(totalDuePerInstallment, interestForInstallment, loanScheduleInfo);
if (interestCalculationGraceOnRepaymentPeriodFraction >= Integer.valueOf(1).doubleValue()) { if (interestCalculationGraceOnRepaymentPeriodFraction >= Integer.valueOf(1).doubleValue()) {
Money graceOnInterestForRepaymentPeriod = interestPerInstallment; Money graceOnInterestForRepaymentPeriod = interestForInstallment;
interestPerInstallment = interestPerInstallment.minus(graceOnInterestForRepaymentPeriod); interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod); totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod);
interestCalculationGraceOnRepaymentPeriodFraction = interestCalculationGraceOnRepaymentPeriodFraction - Integer.valueOf(1).doubleValue(); interestCalculationGraceOnRepaymentPeriodFraction = interestCalculationGraceOnRepaymentPeriodFraction - Integer.valueOf(1).doubleValue();
} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25") && interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) { } else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25") && interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) {
Money graceOnInterestForRepaymentPeriod = interestPerInstallment.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction); Money graceOnInterestForRepaymentPeriod = interestForInstallment.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
interestPerInstallment = interestPerInstallment.minus(graceOnInterestForRepaymentPeriod); interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod); totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod);
interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf("0"); interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf("0");
} }
totalPrincipal = totalPrincipal.plus(principalPerInstallment); totalPrincipal = totalPrincipal.plus(principalForInstallment);
totalInterest = totalInterest.plus(interestPerInstallment); totalInterest = totalInterest.plus(interestForInstallment);
if (installmentNumber == loanScheduleInfo.getNumberOfRepayments()) { if (installmentNumber == loanScheduleInfo.getNumberOfRepayments()) {
Money principalDifference = totalPrincipal.minus(loanScheduleInfo Money principalDifference = totalPrincipal.minus(loanScheduleInfo.getPrincipal());
.getPrincipal());
if (principalDifference.isLessThanZero()) { if (principalDifference.isLessThanZero()) {
principalPerInstallment = principalPerInstallment principalForInstallment = principalForInstallment.plus(principalDifference.abs());
.plus(principalDifference.abs());
} else if (principalDifference.isGreaterThanZero()) { } else if (principalDifference.isGreaterThanZero()) {
principalPerInstallment = principalPerInstallment principalForInstallment = principalForInstallment.minus(principalDifference.abs());
.minus(principalDifference.abs());
} }
Money interestDifference = totalInterest.minus(totalInterestDue); if (loanScheduleInfo.getAmortizationMethod().equals(
if (interestDifference.isLessThanZero()) { AmortizationMethod.EQUAL_INSTALLMENTS)) {
interestPerInstallment = interestPerInstallment Money interestDifference = totalInterest.minus(totalInterestDue);
.plus(interestDifference.abs()); if (interestDifference.isLessThanZero()) {
} else if (interestDifference.isGreaterThanZero()) { interestForInstallment = interestForInstallment.plus(interestDifference.abs());
interestPerInstallment = interestPerInstallment } else if (interestDifference.isGreaterThanZero()) {
.minus(interestDifference.abs()); interestForInstallment = interestForInstallment.minus(interestDifference.abs());
}
} }
} }
Money totalInstallmentDue = principalPerInstallment.plus(interestPerInstallment); Money totalInstallmentDue = principalForInstallment.plus(interestForInstallment);
outstandingBalance = outstandingBalance.minus(principalPerInstallment); outstandingBalance = outstandingBalance.minus(principalForInstallment);
MoneyData principalPerInstallmentValue = MoneyData.of(currencyData, principalPerInstallment.getAmount()); MoneyData principalPerInstallmentValue = MoneyData.of(currencyData, principalForInstallment.getAmount());
MoneyData interestPerInstallmentValue = MoneyData.of(currencyData, interestPerInstallment.getAmount()); MoneyData interestPerInstallmentValue = MoneyData.of(currencyData, interestForInstallment.getAmount());
MoneyData totalInstallmentDueValue = MoneyData.of(currencyData, totalInstallmentDue.getAmount()); MoneyData totalInstallmentDueValue = MoneyData.of(currencyData, totalInstallmentDue.getAmount());
MoneyData outstandingBalanceValue = MoneyData.of(currencyData, outstandingBalance.getAmount()); MoneyData outstandingBalanceValue = MoneyData.of(currencyData, outstandingBalance.getAmount());
@@ -1,41 +1,21 @@
package org.mifosng.platform.loanschedule.domain; package org.mifosng.platform.loanschedule.domain;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.InterestMethod;
public class DefaultLoanScheduleGeneratorFactory implements public class DefaultLoanScheduleGeneratorFactory implements
LoanScheduleGeneratorFactory { LoanScheduleGeneratorFactory {
@Override @Override
public LoanScheduleGenerator create(final InterestMethod interestMethod, public LoanScheduleGenerator create(final InterestMethod interestMethod) {
AmortizationMethod amortizationMethod) {
LoanScheduleGenerator loanScheduleGenerator = null; LoanScheduleGenerator loanScheduleGenerator = null;
switch (amortizationMethod) { switch (interestMethod) {
case EQUAL_PRINCIPAL: case FLAT:
switch (interestMethod) { loanScheduleGenerator = new FlatLoanScheduleGenerator();
case FLAT:
loanScheduleGenerator = new FlatLoanScheduleGenerator();
break;
case DECLINING_BALANCE:
loanScheduleGenerator = new DecliningBalanceLoanScheduleGenerator();
break;
case INVALID:
break;
}
break; break;
case EQUAL_INSTALLMENTS: case DECLINING_BALANCE:
switch (interestMethod) { loanScheduleGenerator = new DecliningBalanceMethodLoanScheduleGenerator();
case FLAT:
loanScheduleGenerator = new FlatLoanScheduleGenerator();
break;
case DECLINING_BALANCE:
loanScheduleGenerator = new DecliningBalanceEqualInstallmentsLoanScheduleGenerator();
break;
case INVALID:
break;
}
break; break;
case INVALID: case INVALID:
break; break;
@@ -1,10 +1,9 @@
package org.mifosng.platform.loanschedule.domain; package org.mifosng.platform.loanschedule.domain;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.InterestMethod;
public interface LoanScheduleGeneratorFactory { public interface LoanScheduleGeneratorFactory {
LoanScheduleGenerator create(InterestMethod interestMethod, AmortizationMethod amortizationMethod); LoanScheduleGenerator create(InterestMethod interestMethod);
} }
@@ -0,0 +1,67 @@
package org.mifosng.platform.loanschedule.domain;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
public class PeriodicInterestRateCalculator {
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
public BigDecimal calculateFrom(LoanProductRelatedDetail loanScheduleInfo) {
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
Integer paymentPeriodsInOneYear = this.paymentPeriodsInOneYearCalculator.calculate(loanScheduleInfo.getRepaymentPeriodFrequencyType());
BigDecimal divisor = BigDecimal.valueOf(paymentPeriodsInOneYear * 100);
BigDecimal numberOfPeriods = BigDecimal.valueOf(loanScheduleInfo.getRepayEvery());
return loanScheduleInfo.getAnnualNominalInterestRate().divide(divisor, mc).multiply(numberOfPeriods);
}
public Money calculateInterestOn(Money outstandingBalance, BigDecimal periodInterestRateForRepaymentPeriod,
int daysInPeriod,
LoanProductRelatedDetail loanScheduleInfo) {
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
Money interestDue = Money.zero(outstandingBalance.getCurrency());
switch (loanScheduleInfo.getInterestCalculationPeriodMethod()) {
case DAILY:
BigDecimal dailyInterestRate = loanScheduleInfo.getAnnualNominalInterestRate()
.divide(BigDecimal.valueOf(Long.valueOf(365)), mc)
.divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc)
.multiply(BigDecimal.valueOf(loanScheduleInfo.getRepayEvery()));
BigDecimal equivalentInterestRateForPeriod = dailyInterestRate.multiply(BigDecimal.valueOf(Long.valueOf(daysInPeriod)));
interestDue = outstandingBalance.multiplyRetainScale(equivalentInterestRateForPeriod, RoundingMode.HALF_EVEN);
break;
default:
interestDue = outstandingBalance.multiplyRetainScale(periodInterestRateForRepaymentPeriod, RoundingMode.HALF_EVEN);
break;
}
return interestDue;
}
public Money calculatePrincipalOn(Money totalDuePerInstallment, Money interestForInstallment, LoanProductRelatedDetail loanScheduleInfo) {
Money principalDue = Money.zero(totalDuePerInstallment.getCurrency());
switch (loanScheduleInfo.getAmortizationMethod()) {
case EQUAL_PRINCIPAL:
principalDue = loanScheduleInfo.getPrincipal().dividedBy(loanScheduleInfo.getNumberOfRepayments(), RoundingMode.HALF_EVEN);
break;
case EQUAL_INSTALLMENTS:
principalDue = totalDuePerInstallment.minus(interestForInstallment);
break;
}
return principalDue;
}
}
@@ -0,0 +1,72 @@
package org.mifosng.platform.loanschedule.domain;
import java.math.BigDecimal;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
public class PmtCalculator {
public Money calculatePaymentForOnePeriodFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) {
// TODO - check if going to doubles is a problem
double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue();
double futureValue = 0;
double numberOfPeriods = loanScheduleInfo.getNumberOfRepayments().doubleValue();
double principal = loanScheduleInfo.getPrincipal().getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue();
// work out the total payment (principal + interest components) for each installment due.
// use the period type and interest as expressed e.g. 2% per month or 24% per year even is 'daily' interest calculation is selected
double paymentPerInstallment = pmt(interestRateFraction, numberOfPeriods, principal, futureValue, false);
return Money.of(monetaryCurrency, BigDecimal.valueOf(paymentPerInstallment));
}
public Money calculateTotalRepaymentFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) {
// TODO - check if going to doubles is a problem
double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue();
double futureValue = 0;
double numberOfPeriods = loanScheduleInfo.getNumberOfRepayments().doubleValue();
double principal = loanScheduleInfo.getPrincipal().getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue();
// work out the total payment (principal + interest components) for each installment due.
// use the period type and interest as expressed e.g. 2% per month or 24% per year even is 'daily' interest calculation is selected
double paymentPerInstallment = pmt(interestRateFraction, numberOfPeriods, principal, futureValue, false);
double totalRepayment = paymentPerInstallment * loanScheduleInfo.getNumberOfRepayments();
return Money.of(monetaryCurrency, BigDecimal.valueOf(totalRepayment));
}
/**
* PMT calculates a fixed monthly payment to be paid by borrower every 'period' to ensure loan is paid off in full (with interest).
*
* This monthly payment c depends upon
* the monthly interest rate r (expressed as a fraction, not a percentage,
* i.e., divide the quoted yearly percentage rate by 100 and by 12 to obtain
* the monthly interest rate), the number of monthly payments N called the
* loan's term, and the amount borrowed P known as the loan's principal; c
* is given by the formula:
*
* c = (r / (1 - (1 + r)^-N))P
*
* @param interestRateFraction
* @param numberOfPayments
* @param principal
* @param futureValue
* @param type
*/
private static double pmt(double interestRateFraction, double numberOfPayments, double principal, double futureValue, boolean type) {
double payment = 0;
if (interestRateFraction == 0) {
payment = -1 * (futureValue + principal) / numberOfPayments;
} else {
double r1 = interestRateFraction + 1;
payment = (futureValue + principal * Math.pow(r1, numberOfPayments)) * interestRateFraction
/ ((type ? r1 : 1) * (1 - Math.pow(r1, numberOfPayments)));
}
return payment;
}
}
@@ -20,7 +20,7 @@ public class PmtTest {
double futureValue = Double.valueOf("0"); double futureValue = Double.valueOf("0");
boolean type = false; boolean type = false;
double payment = DecliningBalanceEqualInstallmentsLoanScheduleGenerator.pmt(interestRateFraction, numberOfPayments, principal, futureValue, type); double payment = DecliningBalanceMethodLoanScheduleGenerator.pmt(interestRateFraction, numberOfPayments, principal, futureValue, type);
assertThat(payment, is(Double.valueOf("13436.317553939027"))); assertThat(payment, is(Double.valueOf("13436.317553939027")));
} }