diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index 80b10685a..02e1b5de9 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -5749,7 +5749,52 @@ GET https://DomainName/api/v1/loans/{loanId}
"disbursementDetails":[{"id":71,"expectedDisbursementDate":[2013,11,1],"principal":22000.000000,"approvedPrincipal":22000.000000}],
"fixedEmiAmount":1100.000000,
"maxOutstandingLoanBalance":35000,
- "canDisburse":false
+ "canDisburse":false,
+ "emiAmountVariations": [],
+ "inArrears": true,
+ "overdueCharges": [
+ {
+ "id": 20,
+ "name": "overdraft penality",
+ "active": true,
+ "penalty": true,
+ "currency": {
+ "code": "USD",
+ "name": "US Dollar",
+ "decimalPlaces": 2,
+ "displaySymbol": "$",
+ "nameCode": "currency.USD",
+ "displayLabel": "US Dollar ($)"
+ },
+ "amount": 3.000000,
+ "chargeTimeType": {
+ "id": 9,
+ "code": "chargeTimeType.overdueInstallment",
+ "value": "overdue fees"
+ },
+ "chargeAppliesTo": {
+ "id": 1,
+ "code": "chargeAppliesTo.loan",
+ "value": "Loan"
+ },
+ "chargeCalculationType": {
+ "id": 2,
+ "code": "chargeCalculationType.percent.of.amount",
+ "value": "% Amount"
+ },
+ "chargePaymentMode": {
+ "id": 0,
+ "code": "chargepaymentmode.regular",
+ "value": "Regular"
+ },
+ "feeInterval": 2,
+ "feeFrequency": {
+ "id": 1,
+ "code": "feeFrequencyperiodFrequencyType.weeks",
+ "value": "Weeks"
+ }
+ }
+ ]
}
}
@@ -12575,9 +12620,15 @@ Request Body:
feeInterval |
- Fee to be applied on a specified interval (number of months).
- This field is mandatory if chargeTimeType is of type Monthly Fee
+ | Fee to be applied on a specified interval.
+ This field is mandatory if chargeTimeType is of type Monthly Fee or feeFrequency is selcted
|
+
+
+ | feeFrequency |
+
+
+ This field is Optional Used to indicate the recurring(days,weeks,months and Years) charge due date starting on system calculated date for overdue penalty.
|
@@ -12627,6 +12678,16 @@ GET https://DomainName/api/v1/charges/template
"id": 2,
"code": "chargeCalculationType.percent.of.amount",
"value": "% Amount"
+ },
+ {
+ "id": 3,
+ "code": "chargeCalculationType.percent.of.amount.and.interest",
+ "value": "% Loan Amount + Interest"
+ },
+ {
+ "id": 4,
+ "code": "chargeCalculationType.percent.of.interest",
+ "value": "% Interest"
}
],
"chargeAppliesToOptions": [
@@ -12671,6 +12732,21 @@ GET https://DomainName/api/v1/charges/template
"id": 7,
"code": "chargeTimeType.monthlyFee",
"value": "Monthly Fee"
+ },
+ {
+ "id": 8,
+ "code": "chargeTimeType.instalmentFee",
+ "value": "Instalment Fee"
+ },
+ {
+ "id": 9,
+ "code": "chargeTimeType.overdueInstallment",
+ "value": "overdue fees"
+ },
+ {
+ "id": 10,
+ "code": "chargeTimeType.overdraftFee",
+ "value": "Overdraft Fee"
}
],
"chargePaymetModeOptions": [
@@ -12695,6 +12771,16 @@ GET https://DomainName/api/v1/charges/template
"id": 2,
"code": "chargeCalculationType.percent.of.amount",
"value": "% Amount"
+ },
+ {
+ "id": 3,
+ "code": "chargeCalculationType.percent.of.amount.and.interest",
+ "value": "% Loan Amount + Interest"
+ },
+ {
+ "id": 4,
+ "code": "chargeCalculationType.percent.of.interest",
+ "value": "% Interest"
}
],
"loanChargeTimeTypeOptions": [
@@ -12707,6 +12793,16 @@ GET https://DomainName/api/v1/charges/template
"id": 2,
"code": "chargeTimeType.specifiedDueDate",
"value": "Specified due date"
+ },
+ {
+ "id": 8,
+ "code": "chargeTimeType.instalmentFee",
+ "value": "Instalment Fee"
+ },
+ {
+ "id": 9,
+ "code": "chargeTimeType.overdueInstallment",
+ "value": "overdue fees"
}
],
"savingsChargeCalculationTypeOptions": [
@@ -12746,6 +12842,33 @@ GET https://DomainName/api/v1/charges/template
"id": 7,
"code": "chargeTimeType.monthlyFee",
"value": "Monthly Fee"
+ },
+ {
+ "id": 10,
+ "code": "chargeTimeType.overdraftFee",
+ "value": "Overdraft Fee"
+ }
+ ],
+ "feeFrequencyOptions": [
+ {
+ "id": 0,
+ "code": "loanTermFrequency.periodFrequencyType.days",
+ "value": "Days"
+ },
+ {
+ "id": 1,
+ "code": "loanTermFrequency.periodFrequencyType.weeks",
+ "value": "Weeks"
+ },
+ {
+ "id": 2,
+ "code": "loanTermFrequency.periodFrequencyType.months",
+ "value": "Months"
+ },
+ {
+ "id": 3,
+ "code": "loanTermFrequency.periodFrequencyType.years",
+ "value": "Years"
}
]
}
@@ -12853,6 +12976,31 @@ Request Body:
{
"resourceId": 6
+}
+
+
+POST charges
+Content-Type: application/json
+Request Body:
+{
+ "chargeAppliesTo":1,
+ "feeFrequency":1,
+ "feeInterval":"2",
+ "name":"overdue charge",
+ "currencyCode":"USD",
+ "chargeTimeType":9,
+ "chargeCalculationType":1,
+ "chargePaymentMode":0,
+ "amount":"50",
+ "active":true,
+ "penalty":"true",
+ "locale":"en",
+ "monthDayFormat":"dd MMM"
+}
+
+
+{
+"resourceId": 7
}
diff --git a/mifosng-db/migrations/core_db/V157__overdue_charge_improvements.sql b/mifosng-db/migrations/core_db/V157__overdue_charge_improvements.sql
new file mode 100755
index 000000000..2ef9233f3
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V157__overdue_charge_improvements.sql
@@ -0,0 +1,18 @@
+ALTER TABLE `m_charge`
+ ADD COLUMN `fee_frequency` SMALLINT(5) NULL DEFAULT NULL AFTER `max_cap`;
+
+CREATE TABLE `m_loan_overdue_installment_charge` (
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `loan_charge_id` BIGINT(20) NOT NULL,
+ `loan_schedule_id` BIGINT(20) NOT NULL,
+ `frequency_number` INT(10) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `FK_m_loan_overdue_installment_charge_m_loan_charge` FOREIGN KEY (`loan_charge_id`) REFERENCES `m_loan_charge` (`id`),
+ CONSTRAINT `FK_m_loan_overdue_installment_charge_m_loan_repayment_schedule` FOREIGN KEY (`loan_schedule_id`) REFERENCES `m_loan_repayment_schedule` (`id`)
+)
+COLLATE='latin1_swedish_ci'
+ENGINE=InnoDB;
+
+INSERT INTO `c_configuration` (`name`, `value`, `enabled`) VALUES ('grace-on-penalty-posting', 0, 1);
+
+INSERT INTO m_loan_overdue_installment_charge (`loan_charge_id`, `loan_schedule_id`, `frequency_number`) SELECT mlc.id ,ls.id ,1 from m_loan_charge as mlc inner join m_charge mc on mc.id = mlc.charge_id inner join m_loan_repayment_schedule ls on ls.loan_id = mlc.loan_id and ls.duedate = mlc.due_for_collection_as_of_date where mc.charge_time_enum = 9 and mlc.is_active = 1;
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java
index 464be38d3..4e1502dda 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -32,4 +32,6 @@ public interface ConfigurationDomainService {
boolean isPasswordForcedResetEnable();
Long retrievePasswordLiveTime();
+
+ Long retrieveGraceOnPenaltyPostingPeriod();
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index 5b13b92ed..fa6ee9bbe 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -113,6 +113,14 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
return property.getValue();
}
+
+ @Override
+ public Long retrieveGraceOnPenaltyPostingPeriod() {
+ final String propertyName = "grace-on-penalty-posting";
+ final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
+ return property.getValue();
+ }
+
@Override
public boolean isPasswordForcedResetEnable() {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java
index 20e6eec60..59b156130 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java
@@ -34,7 +34,7 @@ import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
import org.mifosplatform.portfolio.calendar.domain.CalendarWeekDaysType;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
public class CalendarUtils {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java
index 57f69fd73..cf66548c3 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java
@@ -14,6 +14,7 @@ import org.joda.time.LocalDate;
import org.joda.time.MonthDay;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
+import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeData;
@@ -36,6 +37,7 @@ public class ChargeData implements Comparable, Serializable {
private final Integer feeInterval;
private final BigDecimal minCap;
private final BigDecimal maxCap;
+ private final EnumOptionData feeFrequency;
private final Collection currencyOptions;
private final List chargeCalculationTypeOptions;//
@@ -47,16 +49,19 @@ public class ChargeData implements Comparable, Serializable {
private final List loanChargeTimeTypeOptions;
private final List savingsChargeCalculationTypeOptions;
private final List savingsChargeTimeTypeOptions;
+ private final List feeFrequencyOptions;
public static ChargeData template(final Collection currencyOptions,
final List chargeCalculationTypeOptions, final List chargeAppliesToOptions,
final List chargeTimeTypeOptions, final List chargePaymentModeOptions,
final List loansChargeCalculationTypeOptions, final List loansChargeTimeTypeOptions,
- final List savingsChargeCalculationTypeOptions, final List savingsChargeTimeTypeOptions) {
+ final List savingsChargeCalculationTypeOptions, final List savingsChargeTimeTypeOptions,
+ final List feeFrequencyOptions) {
return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions,
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions,
- loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, null, null, null, null);
+ loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, null, null, null, null,
+ null, feeFrequencyOptions);
}
public static ChargeData withTemplate(final ChargeData charge, final ChargeData template) {
@@ -65,13 +70,13 @@ public class ChargeData implements Comparable, Serializable {
template.chargeCalculationTypeOptions, template.chargeAppliesToOptions, template.chargeTimeTypeOptions,
template.chargePaymetModeOptions, template.loanChargeCalculationTypeOptions, template.loanChargeTimeTypeOptions,
template.savingsChargeCalculationTypeOptions, template.savingsChargeTimeTypeOptions, charge.feeOnMonthDay,
- charge.feeInterval, charge.minCap, charge.maxCap);
+ charge.feeInterval, charge.minCap, charge.maxCap, charge.feeFrequency, template.feeFrequencyOptions);
}
public static ChargeData instance(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
final EnumOptionData chargePaymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, final boolean penalty,
- final boolean active, final BigDecimal minCap, final BigDecimal maxCap) {
+ final boolean active, final BigDecimal minCap, final BigDecimal maxCap, final EnumOptionData feeFrequency) {
final Collection currencyOptions = null;
final List chargeCalculationTypeOptions = null;
@@ -82,11 +87,13 @@ public class ChargeData implements Comparable, Serializable {
final List loansChargeTimeTypeOptions = null;
final List savingsChargeCalculationTypeOptions = null;
final List savingsChargeTimeTypeOptions = null;
+ final List feeFrequencyOptions = null;
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
- savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap);
+ savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap,
+ feeFrequency, feeFrequencyOptions);
}
public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) {
@@ -111,11 +118,14 @@ public class ChargeData implements Comparable, Serializable {
final List loansChargeTimeTypeOptions = null;
final List savingsChargeCalculationTypeOptions = null;
final List savingsChargeTimeTypeOptions = null;
+ final EnumOptionData feeFrequency = null;
+ final List feeFrequencyOptions = null;
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
- savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap);
+ savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap,
+ feeFrequency, feeFrequencyOptions);
}
private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
@@ -126,7 +136,8 @@ public class ChargeData implements Comparable, Serializable {
final List chargePaymentModeOptions, final List loansChargeCalculationTypeOptions,
final List loansChargeTimeTypeOptions, final List savingsChargeCalculationTypeOptions,
final List savingsChargeTimeTypeOptions, final MonthDay feeOnMonthDay, final Integer feeInterval,
- final BigDecimal minCap, final BigDecimal maxCap) {
+ final BigDecimal minCap, final BigDecimal maxCap, final EnumOptionData feeFrequency,
+ final List feeFrequencyOptions) {
this.id = id;
this.name = name;
this.amount = amount;
@@ -150,6 +161,8 @@ public class ChargeData implements Comparable, Serializable {
this.savingsChargeTimeTypeOptions = savingsChargeTimeTypeOptions;
this.loanChargeCalculationTypeOptions = loansChargeCalculationTypeOptions;
this.loanChargeTimeTypeOptions = loansChargeTimeTypeOptions;
+ this.feeFrequency = feeFrequency;
+ this.feeFrequencyOptions = feeFrequencyOptions;
}
@Override
@@ -199,4 +212,17 @@ public class ChargeData implements Comparable, Serializable {
this.chargeCalculationType, percentage, amountPercentageAppliedTo, chargeOptions, this.penalty, this.feeOnMonthDay,
this.feeInterval);
}
+
+
+ public boolean isPenalty() {
+ return this.penalty;
+ }
+
+ public boolean isOverdueInstallmentCharge(){
+ boolean isOverdueInstallmentCharge = false;
+ if(this.chargeTimeType != null){
+ isOverdueInstallmentCharge = ChargeTimeType.fromInt(this.chargeTimeType.getId().intValue()).isOverdueInstallment();
+ }
+ return isOverdueInstallmentCharge;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java
index 4c543c3a9..b0f30250a 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java
@@ -27,6 +27,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.exception.ChargeDueAtDisbursementCannotBePenaltyException;
+import org.mifosplatform.portfolio.charge.exception.ChargeMustBePenaltyException;
import org.mifosplatform.portfolio.charge.exception.ChargeParameterUpdateNotSupportedException;
import org.mifosplatform.portfolio.charge.service.ChargeEnumerations;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
@@ -81,6 +82,9 @@ public class Charge extends AbstractPersistable {
@Column(name = "max_cap", scale = 6, precision = 19, nullable = true)
private BigDecimal maxCap;
+ @Column(name = "fee_frequency", nullable = true)
+ private Integer feeFrequency;
+
public static Charge fromJson(final JsonCommand command) {
final String name = command.stringValueOfParameterNamed("name");
@@ -101,9 +105,10 @@ public class Charge extends AbstractPersistable {
final Integer feeInterval = command.integerValueOfParameterNamed("feeInterval");
final BigDecimal minCap = command.bigDecimalValueOfParameterNamed("minCap");
final BigDecimal maxCap = command.bigDecimalValueOfParameterNamed("maxCap");
+ final Integer feeFrequency = command.integerValueOfParameterNamed("feeFrequency");
return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active, paymentMode,
- feeOnMonthDay, feeInterval, minCap, maxCap);
+ feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency);
}
protected Charge() {
@@ -113,7 +118,7 @@ public class Charge extends AbstractPersistable {
private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo,
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty,
final boolean active, final ChargePaymentMode paymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval,
- final BigDecimal minCap, final BigDecimal maxCap) {
+ final BigDecimal minCap, final BigDecimal maxCap, final Integer feeFrequency) {
this.name = name;
this.amount = amount;
this.currencyCode = currencyCode;
@@ -130,8 +135,9 @@ public class Charge extends AbstractPersistable {
if (isMonthlyFee() || isAnnualFee()) {
this.feeOnMonth = feeOnMonthDay.getMonthOfYear();
this.feeOnDay = feeOnMonthDay.getDayOfMonth();
- this.feeInterval = feeInterval;
}
+ this.feeInterval = feeInterval;
+ this.feeFrequency = feeFrequency;
if (isSavingsCharge()) {
@@ -154,7 +160,7 @@ public class Charge extends AbstractPersistable {
} else if (isLoanCharge()) {
if (penalty && chargeTime.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(name); }
-
+ if (!penalty && chargeTime.isOverdueInstallment()) { throw new ChargeMustBePenaltyException(name); }
if (!isAllowedLoanChargeTime()) {
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTime)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
@@ -381,6 +387,18 @@ public class Charge extends AbstractPersistable {
actualChanges.put("locale", localeAsInput);
this.feeInterval = newValue;
}
+
+ final String feeFrequency = "feeFrequency";
+ if (command.isChangeInIntegerParameterNamed(feeFrequency, this.feeFrequency)) {
+ final Integer newValue = command.integerValueOfParameterNamed(feeFrequency);
+ actualChanges.put(feeFrequency, newValue);
+ actualChanges.put("locale", localeAsInput);
+ this.feeFrequency = newValue;
+ }
+
+ if(this.feeFrequency != null){
+ baseDataValidator.reset().parameter("feeInterval").value(this.feeInterval).notNull();
+ }
final String penaltyParamName = "penalty";
if (command.isChangeInBooleanParameterNamed(penaltyParamName, this.penalty)) {
@@ -415,6 +433,7 @@ public class Charge extends AbstractPersistable {
if (this.penalty && ChargeTimeType.fromInt(this.chargeTime).isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(
this.name); }
+ if (!penalty && ChargeTimeType.fromInt(this.chargeTime).isOverdueInstallment()) { throw new ChargeMustBePenaltyException(name); }
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
@@ -438,9 +457,11 @@ public class Charge extends AbstractPersistable {
final EnumOptionData chargeAppliesTo = ChargeEnumerations.chargeAppliesTo(this.chargeAppliesTo);
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
final EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode);
+ final EnumOptionData feeFrequencyType = ChargeEnumerations.chargePaymentMode(this.feeFrequency);
final CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null);
return ChargeData.instance(getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType,
- chargePaymentmode, getFeeOnMonthDay(), this.feeInterval, this.penalty, this.active, this.minCap, this.maxCap);
+ chargePaymentmode, getFeeOnMonthDay(), this.feeInterval, this.penalty, this.active, this.minCap, this.maxCap,
+ feeFrequencyType);
}
public Integer getChargePaymentMode() {
@@ -455,6 +476,10 @@ public class Charge extends AbstractPersistable {
return ChargeTimeType.fromInt(this.chargeTime).isAnnualFee();
}
+ public boolean isOverdueInstallment() {
+ return ChargeTimeType.fromInt(this.chargeTime).isOverdueInstallment();
+ }
+
public MonthDay getFeeOnMonthDay() {
MonthDay feeOnMonthDay = null;
if (this.feeOnDay != null && this.feeOnMonth != null) {
@@ -466,4 +491,8 @@ public class Charge extends AbstractPersistable {
public Integer feeInterval() {
return this.feeInterval;
}
+
+ public Integer feeFrequency() {
+ return this.feeFrequency;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java
index 11eed65a1..166decf5c 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java
@@ -42,6 +42,11 @@ public enum ChargeTimeType {
return new Integer[] { ChargeTimeType.DISBURSEMENT.getValue(), ChargeTimeType.SPECIFIED_DUE_DATE.getValue(),
ChargeTimeType.INSTALMENT_FEE.getValue(), ChargeTimeType.OVERDUE_INSTALLMENT.getValue() };
}
+
+ public static Object[] validLoanChargeValues() {
+ return new Integer[] { ChargeTimeType.DISBURSEMENT.getValue(), ChargeTimeType.SPECIFIED_DUE_DATE.getValue(),
+ ChargeTimeType.INSTALMENT_FEE.getValue()};
+ }
public static Object[] validSavingsValues() {
return new Integer[] { ChargeTimeType.SPECIFIED_DUE_DATE.getValue(), ChargeTimeType.SAVINGS_ACTIVATION.getValue(),
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/exception/ChargeMustBePenaltyException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/exception/ChargeMustBePenaltyException.java
new file mode 100755
index 000000000..71f0ab768
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/exception/ChargeMustBePenaltyException.java
@@ -0,0 +1,19 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.portfolio.charge.exception;
+
+import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+/**
+ * {@link AbstractPlatformDomainRuleException} thrown when attempting to crate
+ * charge of type penalty due at disbursement .
+ */
+public class ChargeMustBePenaltyException extends AbstractPlatformDomainRuleException {
+
+ public ChargeMustBePenaltyException(final String name) {
+ super("error.msg.charge.must.be.penalty", "Charge '" + name + "' is invalid.", name, name);
+ }
+}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java
index 8ee7fa471..663af9893 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java
@@ -41,7 +41,7 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
*/
private final Set supportedParameters = new HashSet(Arrays.asList("name", "amount", "locale", "currencyCode",
"currencyOptions", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "penalty",
- "active", "chargePaymentMode", "feeOnMonthDay", "feeInterval", "monthDayFormat", "minCap", "maxCap"));
+ "active", "chargePaymentMode", "feeOnMonthDay", "feeInterval", "monthDayFormat", "minCap", "maxCap", "feeFrequency"));
private final FromJsonHelper fromApiJsonHelper;
@@ -70,6 +70,16 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("chargeCalculationType", element);
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull();
+ final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed("feeInterval", element, Locale.getDefault());
+ baseDataValidator.reset().parameter("feeInterval").value(feeInterval).integerGreaterThanZero();
+
+ final Integer feeFrequency = this.fromApiJsonHelper.extractIntegerNamed("feeFrequency", element, Locale.getDefault());
+ baseDataValidator.reset().parameter("feeFrequency").value(feeFrequency).inMinMaxRange(0, 3);
+
+ if (feeFrequency != null) {
+ baseDataValidator.reset().parameter("feeInterval").value(feeInterval).notNull();
+ }
+
final ChargeAppliesTo appliesTo = ChargeAppliesTo.fromInt(chargeAppliesTo);
if (appliesTo.isLoanCharge()) {
// loan applicable validation
@@ -107,7 +117,6 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed("feeOnMonthDay", element);
baseDataValidator.reset().parameter("feeOnMonthDay").value(monthDay).notNull();
- final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed("feeInterval", element, Locale.getDefault());
baseDataValidator.reset().parameter("feeInterval").value(feeInterval).notNull().inMinMaxRange(1, 12);
}
@@ -216,7 +225,7 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
if (this.fromApiJsonHelper.parameterExists("feeInterval", element)) {
final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed("feeInterval", element, Locale.getDefault());
- baseDataValidator.reset().parameter("feeInterval").value(feeInterval).notNull().inMinMaxRange(1, 12);
+ baseDataValidator.reset().parameter("feeInterval").value(feeInterval).integerGreaterThanZero();
}
if (this.fromApiJsonHelper.parameterExists("chargeCalculationType", element)) {
@@ -247,6 +256,10 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("maxCap", element.getAsJsonObject());
baseDataValidator.reset().parameter("maxCap").value(maxCap).notNull().positiveAmount();
}
+ if (this.fromApiJsonHelper.parameterExists("feeFrequency", element)) {
+ final Integer feeFrequency = this.fromApiJsonHelper.extractIntegerNamed("feeFrequency", element, Locale.getDefault());
+ baseDataValidator.reset().parameter("feeFrequency").value(feeFrequency).inMinMaxRange(0, 3);
+ }
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformService.java
index b071b5195..199310c9a 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformService.java
@@ -17,7 +17,7 @@ public interface ChargeReadPlatformService {
ChargeData retrieveNewChargeDetails();
- Collection retrieveLoanApplicableCharges(boolean feeChargesOnly);
+ Collection retrieveLoanApplicableCharges(boolean feeChargesOnly, Integer[] excludeChargeTimes);
Collection retrieveLoanApplicablePenalties();
@@ -28,4 +28,6 @@ public interface ChargeReadPlatformService {
Collection retrieveSavingsAccountApplicablePenalties();
Collection retrieveSavingsProductCharges(Long savingsProductId);
+
+ Collection retrieveLoanProductCharges(Long loanProductId, Integer chargeTime);
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java
index 7d5fd6607..d1857c9f6 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java
@@ -21,6 +21,8 @@ import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformServi
import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
import org.mifosplatform.portfolio.charge.exception.ChargeNotFoundException;
+import org.mifosplatform.portfolio.common.service.CommonEnumerations;
+import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -35,15 +37,18 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
private final PlatformSecurityContext context;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
+ private final DropdownReadPlatformService dropdownReadPlatformService;
@Autowired
public ChargeReadPlatformServiceImpl(final PlatformSecurityContext context,
final CurrencyReadPlatformService currencyReadPlatformService,
- final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource) {
+ final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource,
+ final DropdownReadPlatformService dropdownReadPlatformService) {
this.context = context;
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.currencyReadPlatformService = currencyReadPlatformService;
+ this.dropdownReadPlatformService = dropdownReadPlatformService;
}
@Override
@@ -90,10 +95,11 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
.retrieveSavingsCalculationTypes();
final List savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
.retrieveSavingsCollectionTimeTypes();
+ final List feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions,
allowedChargeTimeOptions, chargePaymentOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
- savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
+ savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeFrequencyOptions);
}
@Override
@@ -109,19 +115,45 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
}
@Override
- public Collection retrieveLoanApplicableCharges(final boolean feeChargesOnly) {
+ public Collection retrieveLoanProductCharges(final Long loanProductId, final Integer chargeTime) {
+
this.context.authenticatedUser();
final ChargeMapper rm = new ChargeMapper();
- String sql = "select " + rm.chargeSchema()
- + " where c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=? order by c.name ";
+ final String sql = "select " + rm.loanProductChargeSchema()
+ + " where c.is_deleted=0 and c.is_active=1 and plc.product_loan_id=? and c.charge_time_enum=?";
+
+ return this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId, chargeTime });
+ }
+
+ @Override
+ public Collection retrieveLoanApplicableCharges(final boolean feeChargesOnly, Integer[] excludeChargeTimes) {
+ this.context.authenticatedUser();
+
+ final ChargeMapper rm = new ChargeMapper();
+ String excludeClause = "";
+ Object[] params = new Object[] { ChargeAppliesTo.LOAN.getValue() };
+ if (excludeChargeTimes != null && excludeChargeTimes.length > 0) {
+ excludeClause = " and c.charge_time_enum not in(?) ";
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < excludeChargeTimes.length; i++) {
+ if (i != 0) {
+ sb.append(",");
+ }
+ sb.append(excludeChargeTimes[i]);
+ }
+ params = new Object[] { ChargeAppliesTo.LOAN.getValue(), sb.toString() };
+ }
+ String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?"
+ + excludeClause + " order by c.name ";
if (feeChargesOnly) {
sql = "select " + rm.chargeSchema()
- + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? order by c.name ";
+ + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? " + excludeClause
+ + "order by c.name ";
}
- return this.jdbcTemplate.query(sql, rm, new Object[] { ChargeAppliesTo.LOAN.getValue() });
+ return this.jdbcTemplate.query(sql, rm, params);
}
@Override
@@ -145,8 +177,8 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
+ "c.is_active as active, oc.name as currencyName, oc.decimal_places as currencyDecimalPlaces, "
+ "oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
+ "oc.internationalized_name_code as currencyNameCode, c.fee_on_day as feeOnDay, c.fee_on_month as feeOnMonth, "
- + "c.fee_interval as feeInterval,c.min_cap as minCap,c.max_cap as maxCap " + "from m_charge c "
- + "join m_organisation_currency oc on c.currency_code = oc.code";
+ + "c.fee_interval as feeInterval, c.fee_frequency as feeFrequency,c.min_cap as minCap,c.max_cap as maxCap "
+ + "from m_charge c " + "join m_organisation_currency oc on c.currency_code = oc.code";
}
public String loanProductChargeSchema() {
@@ -189,6 +221,11 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
final boolean active = rs.getBoolean("active");
final Integer feeInterval = JdbcSupport.getInteger(rs, "feeInterval");
+ EnumOptionData feeFrequencyType = null;
+ final Integer feeFrequency = JdbcSupport.getInteger(rs, "feeFrequency");
+ if (feeFrequency != null) {
+ feeFrequencyType = CommonEnumerations.termFrequencyType(feeFrequency, "feeFrequency");
+ }
MonthDay feeOnMonthDay = null;
final Integer feeOnMonth = JdbcSupport.getInteger(rs, "feeOnMonth");
final Integer feeOnDay = JdbcSupport.getInteger(rs, "feeOnDay");
@@ -199,7 +236,7 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
final BigDecimal maxCap = rs.getBigDecimal("maxCap");
return ChargeData.instance(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType,
- chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active, minCap, maxCap);
+ chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active, minCap, maxCap, feeFrequencyType);
}
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java
index be5ff794e..8c8b726b6 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java
@@ -96,6 +96,10 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP
if (isChargeExistWithLoans || isChargeExistWithSavings) { throw new ChargeCannotBeUpdatedException(
"error.msg.charge.cannot.be.updated.it.is.used.in.loan", "This charge cannot be updated, it is used in loan"); }
}
+ }else if((changes.containsKey("feeFrequency") || changes.containsKey("feeInterval")) && chargeForUpdate.isLoanCharge()){
+ final Boolean isChargeExistWithLoans = isAnyLoanProductsAssociateWithThisCharge(chargeId);
+ if (isChargeExistWithLoans) { throw new ChargeCannotBeUpdatedException(
+ "error.msg.charge.frequency.cannot.be.updated.it.is.used.in.loan", "This charge frequency cannot be updated, it is used in loan"); }
}
if (!changes.isEmpty()) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/PeriodFrequencyType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/domain/PeriodFrequencyType.java
similarity index 96%
rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/PeriodFrequencyType.java
rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/domain/PeriodFrequencyType.java
index 3d1213039..8e8434b33 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/PeriodFrequencyType.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/domain/PeriodFrequencyType.java
@@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-package org.mifosplatform.portfolio.loanproduct.domain;
+package org.mifosplatform.portfolio.common.domain;
public enum PeriodFrequencyType {
DAYS(0, "periodFrequencyType.days"), //
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/CommonEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/CommonEnumerations.java
new file mode 100755
index 000000000..33c06eb78
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/CommonEnumerations.java
@@ -0,0 +1,35 @@
+package org.mifosplatform.portfolio.common.service;
+
+import org.mifosplatform.infrastructure.core.data.EnumOptionData;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
+
+public class CommonEnumerations {
+
+ public static EnumOptionData termFrequencyType(final int id, final String codePrefix) {
+ return termFrequencyType(PeriodFrequencyType.fromInt(id), codePrefix);
+ }
+
+ public static EnumOptionData termFrequencyType(final PeriodFrequencyType type, final String codePrefix) {
+ EnumOptionData optionData = null;
+ switch (type) {
+ case DAYS:
+ optionData = new EnumOptionData(PeriodFrequencyType.DAYS.getValue().longValue(), codePrefix
+ + PeriodFrequencyType.DAYS.getCode(), "Days");
+ break;
+ case WEEKS:
+ optionData = new EnumOptionData(PeriodFrequencyType.WEEKS.getValue().longValue(), codePrefix
+ + PeriodFrequencyType.WEEKS.getCode(), "Weeks");
+ break;
+ case MONTHS:
+ optionData = new EnumOptionData(PeriodFrequencyType.MONTHS.getValue().longValue(), codePrefix
+ + PeriodFrequencyType.MONTHS.getCode(), "Months");
+ break;
+ default:
+ optionData = new EnumOptionData(PeriodFrequencyType.INVALID.getValue().longValue(), PeriodFrequencyType.INVALID.getCode(),
+ "Invalid");
+ break;
+ }
+ return optionData;
+ }
+
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/DropdownReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/DropdownReadPlatformService.java
new file mode 100755
index 000000000..7e96ad23a
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/DropdownReadPlatformService.java
@@ -0,0 +1,11 @@
+package org.mifosplatform.portfolio.common.service;
+
+import java.util.List;
+
+import org.mifosplatform.infrastructure.core.data.EnumOptionData;
+
+
+public interface DropdownReadPlatformService {
+
+ List retrievePeriodFrequencyTypeOptions();
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/DropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/DropdownReadPlatformServiceImpl.java
new file mode 100755
index 000000000..6fb30cba8
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/DropdownReadPlatformServiceImpl.java
@@ -0,0 +1,23 @@
+package org.mifosplatform.portfolio.common.service;
+
+import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.loanTermFrequencyType;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.mifosplatform.infrastructure.core.data.EnumOptionData;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DropdownReadPlatformServiceImpl implements DropdownReadPlatformService{
+
+ @Override
+ public List retrievePeriodFrequencyTypeOptions() {
+ final List loanTermFrequencyOptions = Arrays.asList(loanTermFrequencyType(PeriodFrequencyType.DAYS),
+ loanTermFrequencyType(PeriodFrequencyType.WEEKS), loanTermFrequencyType(PeriodFrequencyType.MONTHS),
+ loanTermFrequencyType(PeriodFrequencyType.YEARS));
+ return loanTermFrequencyOptions;
+ }
+
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanChargesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanChargesApiResource.java
index 950f16979..665f134f9 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanChargesApiResource.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanChargesApiResource.java
@@ -34,6 +34,7 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.charge.data.ChargeData;
+import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
@@ -101,7 +102,7 @@ public class LoanChargesApiResource {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final boolean feeChargesOnly = false;
- final Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
+ final Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly, new Integer[]{ChargeTimeType.OVERDUE_INSTALLMENT.getValue()});
final LoanChargeData loanChargeTemplate = LoanChargeData.template(chargeOptions);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java
index 6727594fa..c6378b624 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java
@@ -52,6 +52,7 @@ import org.mifosplatform.portfolio.account.service.PortfolioAccountReadPlatformS
import org.mifosplatform.portfolio.calendar.data.CalendarData;
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
import org.mifosplatform.portfolio.charge.data.ChargeData;
+import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
@@ -411,7 +412,8 @@ public class LoansApiResource {
fundOptions = this.fundReadPlatformService.retrieveAllFunds();
repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies();
final boolean feeChargesOnly = false;
- chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
+ chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly,
+ new Integer[] { ChargeTimeType.OVERDUE_INSTALLMENT.getValue() });
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(loanBasicDetails.officeId(),
@@ -438,11 +440,15 @@ public class LoansApiResource {
}
+ Collection overdueCharges = this.chargeReadPlatformService.retrieveLoanProductCharges(loanBasicDetails.loanProductId(),
+ ChargeTimeType.OVERDUE_INSTALLMENT.getValue());
+
final LoanAccountData loanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments,
charges, collateral, guarantors, meeting, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
- loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations);
+ loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
+ overdueCharges);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
mandatoryResponseParameters);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java
index 48e36ab63..7e906a689 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java
@@ -158,6 +158,8 @@ public class LoanAccountData {
private final Boolean inArrears;
+ private final Collection overdueCharges;
+
/**
* Used to produce a {@link LoanAccountData} with only collateral options
* for now.
@@ -242,6 +244,7 @@ public class LoanAccountData {
final Map memberVariations = null;
final LoanProductData product = null;
final Boolean inArrears = null;
+ final Collection overdueCharges = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
currencyData, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
@@ -255,7 +258,7 @@ public class LoanAccountData {
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations,
- product, inArrears, graceOnArrearsAgeing);
+ product, inArrears, graceOnArrearsAgeing, overdueCharges);
}
/**
@@ -342,6 +345,7 @@ public class LoanAccountData {
final Map memberVariations = null;
final LoanProductData product = null;
final Boolean inArrears = null;
+ final Collection overdueCharges = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -355,7 +359,7 @@ public class LoanAccountData {
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount,
- maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing);
+ maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges);
}
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
@@ -376,7 +380,7 @@ public class LoanAccountData {
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
- acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing);
+ acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
}
/**
@@ -464,6 +468,7 @@ public class LoanAccountData {
final Map memberVariations = null;
final LoanProductData product = null;
final Boolean inArrears = null;
+ final Collection overdueCharges = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -477,7 +482,7 @@ public class LoanAccountData {
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingBalance,
- emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing);
+ emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges);
}
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
@@ -497,7 +502,7 @@ public class LoanAccountData {
acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
- acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing);
+ acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
}
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
@@ -562,7 +567,9 @@ public class LoanAccountData {
final Collection charges = new ArrayList();
for (final ChargeData charge : product.charges()) {
- charges.add(charge.toLoanChargeData());
+ if (!charge.isOverdueInstallmentCharge()) {
+ charges.add(charge.toLoanChargeData());
+ }
}
final Integer loancounter = null;
@@ -617,7 +624,8 @@ public class LoanAccountData {
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
notes, accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(), fixedEmi,
- product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears, product.getGraceOnArrearsAgeing());
+ product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears,
+ product.getGraceOnArrearsAgeing(), product.overdueFeeCharges());
}
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
@@ -669,7 +677,7 @@ public class LoanAccountData {
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, acc.accountLinkingOptions,
acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), acc.fixedEmiAmount,
product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, acc.inArrears,
- product.getGraceOnArrearsAgeing());
+ product.getGraceOnArrearsAgeing(), product.overdueFeeCharges());
}
/*
@@ -721,6 +729,7 @@ public class LoanAccountData {
final Collection emiAmountVariations = null;
final Map memberVariations = null;
final LoanProductData product = null;
+ final Collection overdueCharges = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -734,7 +743,7 @@ public class LoanAccountData {
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmont, outstandingLoanBalance,
- emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing);
+ emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges);
}
/*
@@ -754,7 +763,7 @@ public class LoanAccountData {
final Collection loanCollateralOptions, final Collection calendarOptions,
final Collection notes, final Collection accountLinkingOptions,
final PortfolioAccountData linkedAccount, final Collection disbursementDetails,
- final Collection emiAmountVariations) {
+ final Collection emiAmountVariations, final Collection overdueCharges) {
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.principal,
@@ -770,7 +779,7 @@ public class LoanAccountData {
loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes,
accountLinkingOptions, linkedAccount, disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount,
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
- acc.graceOnArrearsAgeing);
+ acc.graceOnArrearsAgeing, overdueCharges);
}
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection productOptions,
@@ -781,7 +790,7 @@ public class LoanAccountData {
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
allowedLoanOfficers, acc.loanPurposeOptions, acc.loanCollateralOptions, calendarOptions, acc.notes, accountLinkingOptions,
- acc.linkedAccount, acc.disbursementDetails, acc.emiAmountVariations);
+ acc.linkedAccount, acc.disbursementDetails, acc.emiAmountVariations, acc.overdueCharges);
}
public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) {
@@ -800,7 +809,7 @@ public class LoanAccountData {
acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
- acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing);
+ acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
}
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map memberLoanCycle) {
@@ -856,7 +865,7 @@ public class LoanAccountData {
acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
- acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing);
+ acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
}
private LoanAccountData(
@@ -909,7 +918,8 @@ public class LoanAccountData {
final PortfolioAccountData linkedAccount, final Collection disbursementDetails,
final Boolean multiDisburseLoan, BigDecimal fixedEmiAmount, final BigDecimal maxOutstandingLoanBalance,
final Collection emiAmountVariations, final Map memberVariations,
- final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing) {
+ final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing,
+ final Collection overdueCharges) {
this.id = id;
this.accountNo = accountNo;
this.status = status;
@@ -1046,6 +1056,7 @@ public class LoanAccountData {
this.product = product;
this.inArrears = inArrears;
this.graceOnArrearsAgeing = graceOnArrearsAgeing;
+ this.overdueCharges = overdueCharges;
}
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
@@ -1119,4 +1130,8 @@ public class LoanAccountData {
return this.group;
}
+ public Long loanProductId() {
+ return this.loanProductId;
+ }
+
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
index 2fba56205..c248b7247 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
@@ -66,6 +66,7 @@ import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedExcep
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.fund.domain.Fund;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
@@ -92,7 +93,6 @@ import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.useradministration.domain.AppUser;
@@ -478,6 +478,8 @@ public class Loan extends AbstractPersistable {
chargeAmt = loanCharge.getPercentage();
if (loanCharge.isInstalmentFee()) {
totalChargeAmt = calculatePerInstallmentChargeAmount(loanCharge);
+ } else if (loanCharge.isOverdueInstallmentCharge()) {
+ totalChargeAmt = loanCharge.amountOutstanding();
}
} else {
chargeAmt = loanCharge.amount();
@@ -1940,11 +1942,11 @@ public class Loan extends AbstractPersistable {
loanVariationTermsData.add(data);
}
- final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms
- .assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, getDisbursementDate(),
- getExpectedFirstRepaymentOnDate(), calculatedRepaymentsStartingFromDate, getInArrearsTolerance(),
- this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData,
- this.maxOutstandingLoanBalance,loanVariationTermsData, getInterestChargedFromDate());
+ final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency,
+ loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
+ calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
+ this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
+ loanVariationTermsData, getInterestChargedFromDate());
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, charges(),
isHolidayEnabled, holidays, workingDays);
@@ -2430,18 +2432,17 @@ public class Loan extends AbstractPersistable {
return possibleNextRepaymentDate;
}
- public Money possibleNextRepaymentAmount() {
- final MonetaryCurrency currency = this.loanRepaymentScheduleDetail.getPrincipal().getCurrency();
- Money possibleNextRepaymentAmount = Money.zero(currency);
+ public LoanRepaymentScheduleInstallment possibleNextRepaymentInstallment() {
+ LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = null;
for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
if (installment.isNotFullyPaidOff()) {
- possibleNextRepaymentAmount = installment.getTotalOutstanding(currency);
+ loanRepaymentScheduleInstallment = installment;
break;
}
}
- return possibleNextRepaymentAmount;
+ return loanRepaymentScheduleInstallment;
}
public LoanTransaction deriveDefaultInterestWaiverTransaction() {
@@ -3735,4 +3736,16 @@ public class Loan extends AbstractPersistable {
return emiAmount;
}
+ public LoanRepaymentScheduleInstallment fetchRepaymentScheduleInstallment(final Integer installmentNumber) {
+ LoanRepaymentScheduleInstallment installment = null;
+ if (installmentNumber == null) { return installment; }
+ for (final LoanRepaymentScheduleInstallment scheduleInstallment : this.repaymentScheduleInstallments) {
+ if (scheduleInstallment.getInstallmentNumber().equals(installmentNumber)) {
+ installment = scheduleInstallment;
+ break;
+ }
+ }
+ return installment;
+ }
+
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java
index d3caf2aee..726a2ca38 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java
@@ -18,9 +18,11 @@ import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@@ -111,11 +113,19 @@ public class LoanCharge extends AbstractPersistable {
@Column(name = "is_active", nullable = false)
private boolean active = true;
+
+ @SuppressWarnings("unused")
+ @OneToOne(mappedBy = "loancharge", cascade = CascadeType.ALL, optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
+ private LoanOverdueInstallmentCharge overdueInstallmentCharge;
+
public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
-
- final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
+ return createNewFromJson(loan, chargeDefinition, command,dueDate);
+ }
+
+ public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command,final LocalDate dueDate) {
+ final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");
final ChargeTimeType chargeTime = null;
final ChargeCalculationType chargeCalculation = null;
@@ -123,13 +133,26 @@ public class LoanCharge extends AbstractPersistable {
BigDecimal amountPercentageAppliedTo = BigDecimal.ZERO;
switch (ChargeCalculationType.fromInt(chargeDefinition.getChargeCalculation())) {
case PERCENT_OF_AMOUNT:
- amountPercentageAppliedTo = loan.getPrincpal().getAmount();
+ if (command.hasParameter("principal")) {
+ amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("principal");
+ } else {
+ amountPercentageAppliedTo = loan.getPrincpal().getAmount();
+ }
break;
case PERCENT_OF_AMOUNT_AND_INTEREST:
- amountPercentageAppliedTo = loan.getPrincpal().getAmount().add(loan.getTotalInterest());
+ if (command.hasParameter("principal") && command.hasParameter("interest")) {
+ amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("principal").add(
+ command.bigDecimalValueOfParameterNamed("interest"));
+ } else {
+ amountPercentageAppliedTo = loan.getPrincpal().getAmount().add(loan.getTotalInterest());
+ }
break;
case PERCENT_OF_INTEREST:
- amountPercentageAppliedTo = loan.getTotalInterest();
+ if (command.hasParameter("interest")) {
+ amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("interest");
+ } else {
+ amountPercentageAppliedTo = loan.getTotalInterest();
+ }
break;
default:
break;
@@ -474,6 +497,10 @@ public class LoanCharge extends AbstractPersistable {
return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.INSTALMENT_FEE);
}
+ public boolean isOverdueInstallmentCharge() {
+ return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.OVERDUE_INSTALLMENT);
+ }
+
private static boolean isGreaterThanZero(final BigDecimal value) {
return value.compareTo(BigDecimal.ZERO) == 1;
}
@@ -792,4 +819,23 @@ public class LoanCharge extends AbstractPersistable {
public BigDecimal amountOrPercentage() {
return this.amountOrPercentage;
}
+
+ public BigDecimal chargeAmount() {
+ BigDecimal totalChargeAmount = this.amountOutstanding;
+ if (this.amountPaid != null) {
+ totalChargeAmount = totalChargeAmount.add(this.amountPaid);
+ }
+ if (this.amountWaived != null) {
+ totalChargeAmount = totalChargeAmount.add(this.amountWaived);
+ }
+ if (this.amountWrittenOff != null) {
+ totalChargeAmount = totalChargeAmount.add(this.amountWrittenOff);
+ }
+ return totalChargeAmount;
+ }
+
+
+ public void updateOverdueInstallmentCharge(LoanOverdueInstallmentCharge overdueInstallmentCharge) {
+ this.overdueInstallmentCharge = overdueInstallmentCharge;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java
new file mode 100755
index 000000000..53a8ca4bf
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java
@@ -0,0 +1,45 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.portfolio.loanaccount.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.springframework.data.jpa.domain.AbstractPersistable;
+
+@Entity
+@Table(name = "m_loan_overdue_installment_charge")
+public class LoanOverdueInstallmentCharge extends AbstractPersistable {
+
+ @SuppressWarnings("unused")
+ @ManyToOne(optional = false)
+ @JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false)
+ private LoanCharge loancharge;
+
+ @SuppressWarnings("unused")
+ @ManyToOne(optional = false)
+ @JoinColumn(name = "loan_schedule_id", referencedColumnName = "id", nullable = false)
+ private LoanRepaymentScheduleInstallment installment;
+
+ @SuppressWarnings("unused")
+ @Column(name="frequency_number")
+ private Integer frequencyNumber;
+
+
+ public LoanOverdueInstallmentCharge(){
+
+ }
+
+ public LoanOverdueInstallmentCharge(final LoanCharge loanCharge,final LoanRepaymentScheduleInstallment installment, final Integer frequencyNumber){
+ this.loancharge = loanCharge;
+ this.installment = installment;
+ this.frequencyNumber = frequencyNumber;
+ }
+
+}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
index edee731db..97f542ffb 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
@@ -75,7 +75,11 @@ public class LoanRepaymentScheduleProcessingWrapper {
} else {
cumulative = cumulative.plus(loanCharge.amount().divide(BigDecimal.valueOf(numberOfRepayments)));
}
- } else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
+ }else if (loanCharge.isOverdueInstallmentCharge()
+ && loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
+ && loanCharge.getChargeCalculation().isPercentageBased()) {
+ cumulative = cumulative.plus(loanCharge.chargeAmount());
+ }else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
&& loanCharge.getChargeCalculation().isPercentageBased()) {
BigDecimal amount = BigDecimal.ZERO;
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
@@ -162,6 +166,10 @@ public class LoanRepaymentScheduleProcessingWrapper {
} else {
cumulative = cumulative.plus(loanCharge.amount().divide(BigDecimal.valueOf(numberOfRepayments)));
}
+ }else if (loanCharge.isOverdueInstallmentCharge()
+ && loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
+ && loanCharge.getChargeCalculation().isPercentageBased()) {
+ cumulative = cumulative.plus(loanCharge.chargeAmount());
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
&& loanCharge.getChargeCalculation().isPercentageBased()) {
BigDecimal amount = BigDecimal.ZERO;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/data/OverdueLoanScheduleData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/data/OverdueLoanScheduleData.java
index c9a079f30..401ba34f1 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/data/OverdueLoanScheduleData.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/data/OverdueLoanScheduleData.java
@@ -10,15 +10,22 @@ public class OverdueLoanScheduleData {
private final BigDecimal amount;
private final String dateFormat;
private final String dueDate;
+ private final BigDecimal principalOverdue;
+ private final BigDecimal interestOverdue;
+ private final Integer periodNumber;
public OverdueLoanScheduleData(final Long loanId, final Long chargeId, final String dueDate, final BigDecimal amount,
- final String dateFormat, final String locale) {
+ final String dateFormat, final String locale, final BigDecimal principalOverdue, final BigDecimal interestOverdue,
+ final Integer periodNumber) {
this.loanId = loanId;
this.chargeId = chargeId;
this.dueDate = dueDate;
this.amount = amount;
this.dateFormat = dateFormat;
this.locale = locale;
+ this.principalOverdue = principalOverdue;
+ this.interestOverdue = interestOverdue;
+ this.periodNumber = periodNumber;
}
public Long getLoanId() {
@@ -45,9 +52,16 @@ public class OverdueLoanScheduleData {
return this.locale;
}
+
+ public Integer getPeriodNumber() {
+ return this.periodNumber;
+ }
+
@Override
public String toString() {
return "{" + "chargeId:" + this.chargeId + ", locale:'" + this.locale + '\'' + ", amount:" + this.amount + ", dateFormat:'"
- + this.dateFormat + '\'' + ", dueDate:'" + this.dueDate + '\'' + '}';
+ + this.dateFormat + '\'' + ", dueDate:'" + this.dueDate + '\'' + ", principal:'" + this.principalOverdue + '\''
+ + ", interest:'" + this.interestOverdue + '\'' + '}';
}
+
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
index cd1fc6a14..2c90a3ff2 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
@@ -73,7 +73,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LocalDate periodStartDate = loanApplicationTerms.getExpectedDisbursementDate();
LocalDate actualRepaymentDate = periodStartDate;
boolean isFirstRepayment = true;
- LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(periodStartDate, loanApplicationTerms, isFirstRepayment);
+ LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(periodStartDate, loanApplicationTerms,
+ isFirstRepayment);
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
@@ -91,7 +92,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
outstandingBalance = outstandingBalance.zero().plus(disburseAmt);
}
while (!outstandingBalance.isZero()) {
- actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms, isFirstRepayment);
+ actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
+ isFirstRepayment);
isFirstRepayment = false;
LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms,
isHolidayEnabled, holidays, workingDays);
@@ -298,6 +300,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
} else {
cumulative = cumulative.plus(loanCharge.amount().divide(BigDecimal.valueOf(numberOfRepayments)));
}
+ } else if (loanCharge.isOverdueInstallmentCharge()
+ && loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
+ && loanCharge.getChargeCalculation().isPercentageBased()) {
+ cumulative = cumulative.plus(loanCharge.chargeAmount());
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
&& loanCharge.getChargeCalculation().isPercentageBased()) {
BigDecimal amount = BigDecimal.ZERO;
@@ -344,7 +350,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
} else {
cumulative = cumulative.plus(loanCharge.amount().divide(BigDecimal.valueOf(numberOfRepayments)));
}
- } else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
+ } else if (loanCharge.isOverdueInstallmentCharge()
+ && loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
+ && loanCharge.getChargeCalculation().isPercentageBased()) {
+ cumulative = cumulative.plus(loanCharge.chargeAmount());
+ }else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
&& loanCharge.getChargeCalculation().isPercentageBased()) {
BigDecimal amount = BigDecimal.ZERO;
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AprCalculator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AprCalculator.java
index 1f7ec822c..7c70fd844 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AprCalculator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AprCalculator.java
@@ -7,7 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import java.math.BigDecimal;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.springframework.stereotype.Component;
@Component
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultPaymentPeriodsInOneYearCalculator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultPaymentPeriodsInOneYearCalculator.java
index 83e715c1a..cdeee1b82 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultPaymentPeriodsInOneYearCalculator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultPaymentPeriodsInOneYearCalculator.java
@@ -8,7 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
public class DefaultPaymentPeriodsInOneYearCalculator implements PaymentPeriodsInOneYearCalculator {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
index cc3f19ebe..56911ced1 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
@@ -12,7 +12,7 @@ import org.mifosplatform.organisation.holiday.domain.Holiday;
import org.mifosplatform.organisation.holiday.service.HolidayUtil;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
@@ -33,13 +33,15 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
}
@Override
- public LocalDate generateNextRepaymentDate(final LocalDate lastRepaymentDate, final LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment) {
+ public LocalDate generateNextRepaymentDate(final LocalDate lastRepaymentDate, final LoanApplicationTerms loanApplicationTerms,
+ boolean isFirstRepayment) {
final LocalDate firstRepaymentPeriodDate = loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate();
LocalDate dueRepaymentPeriodDate = null;
if (isFirstRepayment && firstRepaymentPeriodDate != null) {
dueRepaymentPeriodDate = firstRepaymentPeriodDate;
} else {
- dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms, lastRepaymentDate);
+ dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
+ loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate);
}
return dueRepaymentPeriodDate;
}
@@ -48,7 +50,8 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
public LocalDate adjustRepaymentDate(final LocalDate dueRepaymentPeriodDate, final LoanApplicationTerms loanApplicationTerms,
final boolean isHolidayEnabled, final List holidays, final WorkingDays workingDays) {
LocalDate adjustedDate = dueRepaymentPeriodDate;
- final LocalDate nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms, adjustedDate);
+ final LocalDate nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
+ loanApplicationTerms.getRepaymentEvery(), adjustedDate);
adjustedDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(adjustedDate, nextDueRepaymentPeriodDate, workingDays);
if (isHolidayEnabled) {
adjustedDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(adjustedDate, holidays);
@@ -56,10 +59,10 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
return adjustedDate;
}
- private LocalDate getRepaymentPeriodDate(final LoanApplicationTerms loanApplicationTerms, final LocalDate startDate) {
- final int repaidEvery = loanApplicationTerms.getRepaymentEvery();
+ @Override
+ public LocalDate getRepaymentPeriodDate(final PeriodFrequencyType frequency, final int repaidEvery, final LocalDate startDate) {
LocalDate dueRepaymentPeriodDate = startDate;
- switch (loanApplicationTerms.getRepaymentPeriodFrequencyType()) {
+ switch (frequency) {
case DAYS:
dueRepaymentPeriodDate = startDate.plusDays(repaidEvery);
break;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
index 906cf1c91..09ca65bac 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
@@ -16,13 +16,13 @@ import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
public final class LoanApplicationTerms {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/PaymentPeriodsInOneYearCalculator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/PaymentPeriodsInOneYearCalculator.java
index c8b5ae3d0..36a754102 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/PaymentPeriodsInOneYearCalculator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/PaymentPeriodsInOneYearCalculator.java
@@ -6,7 +6,7 @@
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import org.joda.time.LocalDate;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
public interface PaymentPeriodsInOneYearCalculator {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
index 008fbcae4..0406c8e0f 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
@@ -10,7 +10,7 @@ import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.holiday.domain.Holiday;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
public interface ScheduledDateGenerator {
@@ -24,4 +24,7 @@ public interface ScheduledDateGenerator {
LocalDate adjustRepaymentDate(LocalDate dueRepaymentPeriodDate, LoanApplicationTerms loanApplicationTerms, boolean isHolidayEnabled,
List holidays, WorkingDays workingDays);
+
+ LocalDate getRepaymentPeriodDate(PeriodFrequencyType frequency, int repaidEvery, LocalDate startDate);
+
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index b353bf164..df4a8257d 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -35,6 +35,7 @@ import org.mifosplatform.portfolio.calendar.exception.MeetingFrequencyMismatchEx
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper;
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
@@ -56,7 +57,6 @@ import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeAssembler.java
index 53ecc2581..bbf46ae5e 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeAssembler.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeAssembler.java
@@ -17,6 +17,7 @@ import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
+import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
@@ -71,6 +72,14 @@ public class LoanChargeAssembler {
locale);
if (id == null) {
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
+
+ if (chargeDefinition.isOverdueInstallment()) {
+
+ final String defaultUserMessage = "Installment charge cannot be added to the loan.";
+ throw new LoanChargeCannotBeAddedException("loanCharge", "overdue.charge",
+ defaultUserMessage, null, chargeDefinition.getName());
+ }
+
ChargeTimeType chargeTime = null;
if (chargeTimeType != null) {
chargeTime = ChargeTimeType.fromInt(chargeTimeType);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformService.java
index 727e94945..4ccdbf37e 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformService.java
@@ -22,4 +22,6 @@ public interface LoanChargeReadPlatformService {
Collection retrieveLoanChargesForFeePayment(Integer paymentMode, Integer loanStatus);
Collection retrieveInstallmentLoanCharges(Long loanChargeId, boolean onlyPaymentPendingCharges);
+
+ Collection retrieveOverdueInstallmentChargeFrequencyNumber(Long installmentId, Long chargeId);
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
index 45050c2a4..34b4eb071 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
@@ -20,6 +20,7 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.service.ChargeDropdownReadPlatformService;
import org.mifosplatform.portfolio.charge.service.ChargeEnumerations;
+import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,13 +34,16 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
+ private final DropdownReadPlatformService dropdownReadPlatformService;
@Autowired
public LoanChargeReadPlatformServiceImpl(final PlatformSecurityContext context,
- final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource) {
+ final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource,
+ final DropdownReadPlatformService dropdownReadPlatformService) {
this.context = context;
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
+ this.dropdownReadPlatformService = dropdownReadPlatformService;
}
private static final class LoanChargeMapper implements RowMapper {
@@ -128,10 +132,11 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
.retrieveSavingsCalculationTypes();
final List savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
.retrieveSavingsCollectionTimeTypes();
+ final List feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
- savingsChargeTimeTypeOptions);
+ savingsChargeTimeTypeOptions, feeFrequencyOptions);
}
@Override
@@ -219,4 +224,15 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
return new LoanInstallmentChargeData(installmentNumber, dueAsOfDate, amount, amountOutstanding, paid, waived);
}
}
+
+ @Override
+ public Collection retrieveOverdueInstallmentChargeFrequencyNumber(final Long installmentId,final Long chargeId) {
+ String sql = "select oic.frequency_number from m_loan_overdue_installment_charge oic inner join m_loan_charge lc on lc.id=oic.loan_charge_id where oic.loan_schedule_id = ? and lc.is_active = 1";
+ Object[] params = {installmentId};
+ if(chargeId != null){
+ sql += " and lc.charge_id = ? ";
+ params = new Object[]{installmentId,chargeId};
+ }
+ return this.jdbcTemplate.queryForList(sql, Integer.class, params);
+ }
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformService.java
index 90ac0a6f9..ce737e09a 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformService.java
@@ -66,7 +66,7 @@ public interface LoanReadPlatformService {
* result overdue installments with this charge already applied are not
* returned.
*/
- Collection retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized(final Long penaltyWaitPeriod);
+ Collection retrieveAllLoansWithOverdueInstallments(final Long penaltyWaitPeriod);
Integer retriveLoanCounter(Long groupId, Integer loanType, Long productId);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 3af9ca082..39ecb9462 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -39,6 +39,7 @@ import org.mifosplatform.portfolio.calendar.data.CalendarData;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
import org.mifosplatform.portfolio.charge.data.ChargeData;
+import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.domain.ClientEnumerations;
@@ -59,6 +60,7 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
+import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
@@ -337,12 +339,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final LocalDate earliestUnpaidInstallmentDate = loan.possibleNextRepaymentDate();
- final Money possibleNextRepaymentAmount = loan.possibleNextRepaymentAmount();
+ final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.possibleNextRepaymentInstallment();
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
final Collection paymentOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
- possibleNextRepaymentAmount.getAmount(), null, null, null, null, null, paymentOptions, null, null, null);
+ loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment
+ .getPrincipalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment.getInterestOutstanding(currency)
+ .getAmount(), loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency).getAmount(),
+ loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, paymentOptions, null, null, null);
}
@Override
@@ -740,8 +745,23 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final String dueDate = rs.getString("dueDate");
final String locale = "en_GB";
+ final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDue");
+ final BigDecimal principalPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalPaid");
+ final BigDecimal principalWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalWrittenOff");
+
+ final BigDecimal principalOutstanding = principalDue.subtract(principalPaid).subtract(principalWrittenOff);
+
+ final BigDecimal interestExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestDue");
+ final BigDecimal interestPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestPaid");
+ final BigDecimal interestWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWaived");
+ final BigDecimal interestWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWrittenOff");
+
+ final BigDecimal interestActualDue = interestExpectedDue.subtract(interestWaived).subtract(interestWrittenOff);
+ final BigDecimal interestOutstanding = interestActualDue.subtract(interestPaid);
+
+ final Integer installmentNumber = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "period");
final OverdueLoanScheduleData overdueLoanScheduleData = new OverdueLoanScheduleData(loanId, chargeId, dueDate, amount,
- dateFormat, locale);
+ dateFormat, locale, principalOutstanding, interestOutstanding, installmentNumber);
return overdueLoanScheduleData;
}
@@ -1115,7 +1135,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Collection loanCollateralOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode("LoanCollateral");
final boolean feeChargesOnly = false;
- final Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
+ final Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly,
+ new Integer[] { ChargeTimeType.OVERDUE_INSTALLMENT.getValue() });
Integer loanCycleCounter = null;
if (loanProduct.useBorrowerCycle()) {
if (clientId == null) {
@@ -1201,14 +1222,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
- public Collection retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized(final Long penaltyWaitPeriod) {
+ public Collection retrieveAllLoansWithOverdueInstallments(final Long penaltyWaitPeriod) {
final MusoniOverdueLoanScheduleMapper rm = new MusoniOverdueLoanScheduleMapper();
- final String sql = "select "
- + rm.schema()
- + " where DATE_SUB(CURDATE(),INTERVAL ? DAY) > ls.duedate "
+ final String sql = "select " + rm.schema() + " where DATE_SUB(CURDATE(),INTERVAL ? DAY) > ls.duedate "
+ " and ls.completed_derived <> 1 and mc.charge_applies_to_enum =1 "
- + " and mc.charge_time_enum = 9 and ml.loan_status_id = 300 "
- + " and plc.charge_id not in (SELECT charge_id from m_loan_charge as mlc where mlc.loan_id = ml.id and mlc.charge_id = plc.charge_id and mlc.is_active = 1 and mlc.due_for_collection_as_of_date > fromdate AND mlc.due_for_collection_as_of_date <= duedate) ";
+ + " and mc.charge_time_enum = 9 and ml.loan_status_id = 300 ";
return this.jdbcTemplate.query(sql, rm, new Object[] { penaltyWaitPeriod });
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index c46f79d71..f59c3d353 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -61,6 +61,7 @@ import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
+import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBePayedException;
@@ -76,6 +77,7 @@ import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDi
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleRepaymentCommand;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
@@ -90,6 +92,8 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanDisbursementDetails;
import org.mifosplatform.portfolio.loanaccount.domain.LoanInstallmentCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
+import org.mifosplatform.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
+import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
@@ -100,7 +104,9 @@ import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentEx
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
+import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
+import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
@@ -151,7 +157,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
- private final LoanChargeReadPlatformService LoanChargeReadPlatformService;
+ private final LoanChargeReadPlatformService loanChargeReadPlatformService;
private final LoanReadPlatformService loanReadPlatformService;
private final FromJsonHelper fromApiJsonHelper;
private final AccountTransferRepository accountTransferRepository;
@@ -196,7 +202,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
- this.LoanChargeReadPlatformService = loanChargeReadPlatformService;
+ this.loanChargeReadPlatformService = loanChargeReadPlatformService;
this.loanReadPlatformService = loanReadPlatformService;
this.fromApiJsonHelper = fromApiJsonHelper;
this.accountTransferRepository = accountTransferRepository;
@@ -971,6 +977,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
}
+ if (chargeDefinition.isOverdueInstallment()) {
+
+ final String defaultUserMessage = "Installment charge cannot be added to the loan.";
+ throw new LoanChargeCannotBeAddedException("loanCharge", "overdue.charge", defaultUserMessage, null, chargeDefinition.getName());
+ }
+
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
if (portfolioAccountData == null) {
@@ -1226,13 +1238,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override
@CronTarget(jobName = JobName.TRANSFER_FEE_CHARGE_FOR_LOANS)
public void transferFeeCharges() throws JobExecutionException {
- final Collection chargeDatas = this.LoanChargeReadPlatformService.retrieveLoanChargesForFeePayment(
+ final Collection chargeDatas = this.loanChargeReadPlatformService.retrieveLoanChargesForFeePayment(
ChargePaymentMode.ACCOUNT_TRANSFER.getValue(), LoanStatus.ACTIVE.getValue());
final StringBuilder sb = new StringBuilder();
if (chargeDatas != null) {
for (final LoanChargeData chargeData : chargeDatas) {
if (chargeData.isInstallmentFee()) {
- final Collection chargePerInstallments = this.LoanChargeReadPlatformService
+ final Collection chargePerInstallments = this.loanChargeReadPlatformService
.retrieveInstallmentLoanCharges(chargeData.getId(), true);
PortfolioAccountData portfolioAccountData = null;
for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
@@ -1734,7 +1746,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Long penaltyWaitPeriodValue = this.configurationDomainService.retrievePenaltyWaitPeriod();
final Collection overdueLoanScheduledInstallments = this.loanReadPlatformService
- .retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized(penaltyWaitPeriodValue);
+ .retrieveAllLoansWithOverdueInstallments(penaltyWaitPeriodValue);
if (!overdueLoanScheduledInstallments.isEmpty()) {
for (final OverdueLoanScheduleData overdueInstallment : overdueLoanScheduledInstallments) {
@@ -1745,7 +1757,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final JsonCommand command = JsonCommand.from(overdueInstallment.toString(), parsedCommand, this.fromApiJsonHelper,
null, null, null, null, null, overdueInstallment.getLoanId(), null, null, null, null, null, null, null);
- applyChargeToOverdueLoanInstallment(overdueInstallment.getLoanId(), overdueInstallment.getChargeId(), command);
+ applyChargeToOverdueLoanInstallment(overdueInstallment.getLoanId(), overdueInstallment.getChargeId(),
+ overdueInstallment.getPeriodNumber(), command);
} catch (final PlatformApiDataValidationException e) {
final List errors = e.getErrors();
@@ -1759,50 +1772,90 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
@Transactional
- public void applyChargeToOverdueLoanInstallment(final Long loanId, final Long loanChargeId, final JsonCommand command) {
+ public void applyChargeToOverdueLoanInstallment(final Long loanId, final Long loanChargeId, final Integer periodNumber,
+ final JsonCommand command) {
final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan);
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(loanChargeId);
+ final LoanRepaymentScheduleInstallment installment = loan.fetchRepaymentScheduleInstallment(periodNumber);
- final LoanCharge loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, command);
+ Collection frequencyNumbers = loanChargeReadPlatformService.retrieveOverdueInstallmentChargeFrequencyNumber(
+ installment.getId(), chargeDefinition.getId());
- if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
- final String errorMessage = "Charge and Loan must have the same currency.";
- throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
+ Integer feeFrequency = chargeDefinition.feeFrequency();
+ final ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
+ Map scheduleDates = new HashMap();
+ final Long penaltyWaitPeriodValue = this.configurationDomainService.retrievePenaltyWaitPeriod();
+ final Long penaltyPostingWaitPeriodValue = this.configurationDomainService.retrieveGraceOnPenaltyPostingPeriod();
+ final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
+ Long diff = penaltyWaitPeriodValue + 1 - penaltyPostingWaitPeriodValue;
+ if (diff < 0) {
+ diff = 0L;
}
+ LocalDate startDate = dueDate.plusDays(penaltyWaitPeriodValue.intValue() + 1);
+ Integer frequencyNunber = 1;
+ if (feeFrequency == null) {
+ scheduleDates.put(frequencyNunber++, startDate.minusDays(diff.intValue()));
+ } else {
+ while (new LocalDate().isAfter(startDate)) {
+ scheduleDates.put(frequencyNunber++, startDate.minusDays(diff.intValue()));
+ LocalDate scheduleDate = scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency),
+ chargeDefinition.feeInterval(), startDate);
- if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
- final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
- if (portfolioAccountData == null) {
- final String errorMessage = loanCharge.name() + "Charge requires linked savings account for payment";
- throw new LinkedAccountRequiredException("loanCharge.add", errorMessage, loanCharge.name());
+ startDate = scheduleDate;
}
}
- final List existingTransactionIds = new ArrayList();
- final List existingReversedTransactionIds = new ArrayList();
- this.loanChargeRepository.save(loanCharge);
+ for (Integer frequency : frequencyNumbers) {
+ scheduleDates.remove(frequency);
+ }
- final ChangedTransactionDetail changedTransactionDetail = loan.addLoanCharge(loanCharge, existingTransactionIds,
- existingReversedTransactionIds);
+ for (Map.Entry entry : scheduleDates.entrySet()) {
- // we want to apply charge transactions only for those loans charges
- // that are applied when a loan is active
- if (loan.status().isActive()) {
- final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null);
- this.loanTransactionRepository.save(applyLoanChargeTransaction);
- this.loanRepository.saveAndFlush(loan);
- if (changedTransactionDetail != null) {
- for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
- this.loanTransactionRepository.save(mapEntry.getValue());
- this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
+ final LoanCharge loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, command, entry.getValue());
+
+ if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
+ final String errorMessage = "Charge and Loan must have the same currency.";
+ throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
+ }
+
+ if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
+ final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
+ .retriveLoanAssociation(loanId);
+ if (portfolioAccountData == null) {
+ final String errorMessage = loanCharge.name() + "Charge requires linked savings account for payment";
+ throw new LinkedAccountRequiredException("loanCharge.add", errorMessage, loanCharge.name());
}
}
- // we post Journal entries only for loans in active status
- postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
+ LoanOverdueInstallmentCharge overdueInstallmentCharge = new LoanOverdueInstallmentCharge(loanCharge, installment,
+ entry.getKey());
+ loanCharge.updateOverdueInstallmentCharge(overdueInstallmentCharge);
+ final List existingTransactionIds = new ArrayList();
+ final List existingReversedTransactionIds = new ArrayList();
+ this.loanChargeRepository.save(loanCharge);
+
+ final ChangedTransactionDetail changedTransactionDetail = loan.addLoanCharge(loanCharge, existingTransactionIds,
+ existingReversedTransactionIds);
+
+ // we want to apply charge transactions only for those loans charges
+ // that are applied when a loan is active
+ if (loan.status().isActive()) {
+ final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null);
+ this.loanTransactionRepository.save(applyLoanChargeTransaction);
+ this.loanRepository.saveAndFlush(loan);
+ if (changedTransactionDetail != null) {
+ for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
+ this.loanTransactionRepository.save(mapEntry.getValue());
+ this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
+ }
+ }
+
+ // we post Journal entries only for loans in active status
+ postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
+ }
}
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java
index cf50b8370..1fcf984bb 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java
@@ -231,7 +231,7 @@ public class LoanProductsApiResource {
private LoanProductData handleTemplate(final LoanProductData productData) {
final boolean feeChargesOnly = true;
- Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
+ Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly, null);
if (chargeOptions.isEmpty()) {
chargeOptions = null;
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java
index 39ba2a539..2633074c0 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java
@@ -21,11 +21,11 @@ import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.charge.data.ChargeData;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.fund.data.FundData;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
/**
@@ -659,4 +659,15 @@ public class LoanProductData {
public Integer getGraceOnArrearsAgeing() {
return this.graceOnArrearsAgeing;
}
+
+ public Collection overdueFeeCharges(){
+ Collection overdueFeeCharges = new ArrayList();
+ Collection charges = charges();
+ for(ChargeData chargeData : charges){
+ if(chargeData.isOverdueInstallmentCharge()){
+ overdueFeeCharges.add(chargeData);
+ }
+ }
+ return overdueFeeCharges;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java
index 40d397939..d79fb3ed0 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java
@@ -38,6 +38,7 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.charge.domain.Charge;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.fund.domain.Fund;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductMinimumRepaymentScheduleRelatedDetail.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductMinimumRepaymentScheduleRelatedDetail.java
index 8b7b40151..978fe33fd 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductMinimumRepaymentScheduleRelatedDetail.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductMinimumRepaymentScheduleRelatedDetail.java
@@ -5,6 +5,8 @@
*/
package org.mifosplatform.portfolio.loanproduct.domain;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
+
/**
* Represents the bare minimum repayment details needed for activities related
* to generating repayment schedules.
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
index 62447f9e5..4d0ac2d75 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
@@ -23,6 +23,7 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java
index 2c0201adf..4453285e7 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java
@@ -19,6 +19,7 @@ import java.util.Collection;
import java.util.List;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository;
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
@@ -26,7 +27,6 @@ import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodM
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductValueConditionType;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java
index b8d7726ab..0f501950e 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanproduct.service;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.accountdetails.service.AccountEnumerations;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
@@ -17,7 +18,6 @@ import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodM
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductParamType;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductValueConditionType;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
public class LoanEnumerations {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
index 7e5988603..3ce998ed8 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
@@ -65,8 +65,8 @@ import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
import org.mifosplatform.portfolio.client.domain.Client;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.group.domain.Group;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java
index 34d4f8920..b12ad182d 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java
@@ -23,6 +23,7 @@ import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
import org.mifosplatform.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
import org.mifosplatform.portfolio.charge.service.ChargeDropdownReadPlatformService;
import org.mifosplatform.portfolio.charge.service.ChargeEnumerations;
+import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeData;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
@@ -38,17 +39,20 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
+ private final DropdownReadPlatformService dropdownReadPlatformService;
// mappers
private final SavingsAccountChargeDueMapper chargeDueMapper;
@Autowired
public SavingsAccountChargeReadPlatformServiceImpl(final PlatformSecurityContext context,
- final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource) {
+ final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource,
+ final DropdownReadPlatformService dropdownReadPlatformService) {
this.context = context;
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.chargeDueMapper = new SavingsAccountChargeDueMapper();
+ this.dropdownReadPlatformService = dropdownReadPlatformService;
}
private static final class SavingsAccountChargeMapper implements RowMapper {
@@ -138,10 +142,12 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
final List savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
.retrieveSavingsCollectionTimeTypes();
+ final List feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
+
// TODO AA : revisit for merge conflict - Not sure method signature
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
- savingsChargeTimeTypeOptions);
+ savingsChargeTimeTypeOptions, feeFrequencyOptions);
}
@Override
diff --git a/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java b/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java
index e071bedb0..6f2bd757c 100644
--- a/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java
+++ b/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java
@@ -3,12 +3,12 @@ package org.mifosplatform.portfolio.loanaccount;
import java.math.BigDecimal;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
+import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
-import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
/**
* This class is used to keep in one place configurations for setting up