merging MIFOSX-1923
This commit is contained in:
+5
@@ -203,6 +203,11 @@ public class LoanTransactionHelper {
|
|||||||
return (Integer) response.get("resourceId");
|
return (Integer) response.get("resourceId");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object addChargesForAllreadyDisursedLoan(final Integer loanId, final String request, final ResponseSpecification responseSpecification) {
|
||||||
|
final String ADD_CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges?" + Utils.TENANT_IDENTIFIER;
|
||||||
|
return Utils.performServerPost(this.requestSpec, responseSpecification, ADD_CHARGES_URL, request, "");
|
||||||
|
}
|
||||||
|
|
||||||
public Integer updateChargesForLoan(final Integer loanId, final Integer loanchargeId, final String request) {
|
public Integer updateChargesForLoan(final Integer loanId, final Integer loanchargeId, final String request) {
|
||||||
System.out.println("--------------------------------- ADD CHARGES FOR LOAN --------------------------------");
|
System.out.println("--------------------------------- ADD CHARGES FOR LOAN --------------------------------");
|
||||||
final String UPDATE_CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId + "?"
|
final String UPDATE_CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId + "?"
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
|||||||
final List<EnumOptionData> feeFrequencyOptions = null;
|
final List<EnumOptionData> feeFrequencyOptions = null;
|
||||||
final GLAccountData account = null;
|
final GLAccountData account = null;
|
||||||
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null;
|
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null;
|
||||||
|
|
||||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
||||||
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
||||||
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||||
|
|||||||
+38
-26
@@ -56,7 +56,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
private Integer chargeAppliesTo;
|
private Integer chargeAppliesTo;
|
||||||
|
|
||||||
@Column(name = "charge_time_enum", nullable = false)
|
@Column(name = "charge_time_enum", nullable = false)
|
||||||
private Integer chargeTime;
|
private Integer chargeTimeType;
|
||||||
|
|
||||||
@Column(name = "charge_calculation_enum")
|
@Column(name = "charge_calculation_enum")
|
||||||
private Integer chargeCalculation;
|
private Integer chargeCalculation;
|
||||||
@@ -133,7 +133,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.currencyCode = currencyCode;
|
this.currencyCode = currencyCode;
|
||||||
this.chargeAppliesTo = chargeAppliesTo.getValue();
|
this.chargeAppliesTo = chargeAppliesTo.getValue();
|
||||||
this.chargeTime = chargeTime.getValue();
|
this.chargeTimeType = chargeTime.getValue();
|
||||||
this.chargeCalculation = chargeCalculationType.getValue();
|
this.chargeCalculation = chargeCalculationType.getValue();
|
||||||
this.penalty = penalty;
|
this.penalty = penalty;
|
||||||
this.active = active;
|
this.active = active;
|
||||||
@@ -154,7 +154,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
// TODO vishwas, this validation seems unnecessary as identical
|
// TODO vishwas, this validation seems unnecessary as identical
|
||||||
// validation is performed in the write service
|
// validation is performed in the write service
|
||||||
if (!isAllowedSavingsChargeTime()) {
|
if (!isAllowedSavingsChargeTime()) {
|
||||||
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTime)
|
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.savings");
|
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.savings");
|
||||||
}
|
}
|
||||||
// TODO vishwas, this validation seems unnecessary as identical
|
// TODO vishwas, this validation seems unnecessary as identical
|
||||||
@@ -164,7 +164,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
|
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ChargeTimeType.fromInt(getChargeTime()).isWithdrawalFee()
|
if (!ChargeTimeType.fromInt(getChargeTimeType()).isWithdrawalFee()
|
||||||
&& ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
|
&& ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
|
||||||
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("savings.charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
.failWithCodeNoParameterAddedToErrorCode("savings.charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
||||||
@@ -172,16 +172,17 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
} else if (isLoanCharge()) {
|
} else if (isLoanCharge()) {
|
||||||
|
|
||||||
if (penalty && chargeTime.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(name); }
|
if (penalty && (chargeTime.isTimeOfDisbursement()
|
||||||
|
|| chargeTime.isTrancheDisbursement())) { throw new ChargeDueAtDisbursementCannotBePenaltyException(name); }
|
||||||
if (!penalty && chargeTime.isOverdueInstallment()) { throw new ChargeMustBePenaltyException(name); }
|
if (!penalty && chargeTime.isOverdueInstallment()) { throw new ChargeMustBePenaltyException(name); }
|
||||||
// TODO vishwas, this validation seems unnecessary as identical
|
// TODO vishwas, this validation seems unnecessary as identical
|
||||||
// validation is performed in the write service
|
// validation is performed in the write service
|
||||||
if (!isAllowedLoanChargeTime()) {
|
if (!isAllowedLoanChargeTime()) {
|
||||||
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTime)
|
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
|
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPercentageOfAmount()) {
|
if (isPercentageOfApprovedAmount()) {
|
||||||
this.minCap = minCap;
|
this.minCap = minCap;
|
||||||
this.maxCap = maxCap;
|
this.maxCap = maxCap;
|
||||||
}
|
}
|
||||||
@@ -219,8 +220,8 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
return this.currencyCode;
|
return this.currencyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getChargeTime() {
|
public Integer getChargeTimeType() {
|
||||||
return this.chargeTime;
|
return this.chargeTimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getChargeCalculation() {
|
public Integer getChargeCalculation() {
|
||||||
@@ -244,11 +245,11 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowedLoanChargeTime() {
|
public boolean isAllowedLoanChargeTime() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).isAllowedLoanChargeTime();
|
return ChargeTimeType.fromInt(this.chargeTimeType).isAllowedLoanChargeTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowedClientChargeTime() {
|
public boolean isAllowedClientChargeTime() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).isAllowedClientChargeTime();
|
return ChargeTimeType.fromInt(this.chargeTimeType).isAllowedClientChargeTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSavingsCharge() {
|
public boolean isSavingsCharge() {
|
||||||
@@ -260,7 +261,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowedSavingsChargeTime() {
|
public boolean isAllowedSavingsChargeTime() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).isAllowedSavingsChargeTime();
|
return ChargeTimeType.fromInt(this.chargeTimeType).isAllowedSavingsChargeTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowedSavingsChargeCalculationType() {
|
public boolean isAllowedSavingsChargeCalculationType() {
|
||||||
@@ -271,10 +272,14 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
return ChargeCalculationType.fromInt(this.chargeCalculation).isAllowedClientChargeCalculationType();
|
return ChargeCalculationType.fromInt(this.chargeCalculation).isAllowedClientChargeCalculationType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPercentageOfAmount() {
|
public boolean isPercentageOfApprovedAmount() {
|
||||||
return ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfAmount();
|
return ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPercentageOfDisbursementAmount() {
|
||||||
|
return ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfDisbursementAmount();
|
||||||
|
}
|
||||||
|
|
||||||
public BigDecimal getMinCap() {
|
public BigDecimal getMinCap() {
|
||||||
return this.minCap;
|
return this.minCap;
|
||||||
}
|
}
|
||||||
@@ -315,15 +320,15 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String chargeTimeParamName = "chargeTimeType";
|
final String chargeTimeParamName = "chargeTimeType";
|
||||||
if (command.isChangeInIntegerParameterNamed(chargeTimeParamName, this.chargeTime)) {
|
if (command.isChangeInIntegerParameterNamed(chargeTimeParamName, this.chargeTimeType)) {
|
||||||
final Integer newValue = command.integerValueOfParameterNamed(chargeTimeParamName);
|
final Integer newValue = command.integerValueOfParameterNamed(chargeTimeParamName);
|
||||||
actualChanges.put(chargeTimeParamName, newValue);
|
actualChanges.put(chargeTimeParamName, newValue);
|
||||||
actualChanges.put("locale", localeAsInput);
|
actualChanges.put("locale", localeAsInput);
|
||||||
this.chargeTime = ChargeTimeType.fromInt(newValue).getValue();
|
this.chargeTimeType = ChargeTimeType.fromInt(newValue).getValue();
|
||||||
|
|
||||||
if (isSavingsCharge()) {
|
if (isSavingsCharge()) {
|
||||||
if (!isAllowedSavingsChargeTime()) {
|
if (!isAllowedSavingsChargeTime()) {
|
||||||
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTime)
|
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.savings");
|
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.savings");
|
||||||
}
|
}
|
||||||
// if charge time is changed to monthly then validate for
|
// if charge time is changed to monthly then validate for
|
||||||
@@ -337,12 +342,12 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
} else if (isLoanCharge()) {
|
} else if (isLoanCharge()) {
|
||||||
if (!isAllowedLoanChargeTime()) {
|
if (!isAllowedLoanChargeTime()) {
|
||||||
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTime)
|
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
|
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
|
||||||
}
|
}
|
||||||
} else if (isClientCharge()) {
|
} else if (isClientCharge()) {
|
||||||
if (!isAllowedLoanChargeTime()) {
|
if (!isAllowedLoanChargeTime()) {
|
||||||
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTime)
|
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.client");
|
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,7 +381,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
|
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ChargeTimeType.fromInt(getChargeTime()).isWithdrawalFee()
|
if (!ChargeTimeType.fromInt(getChargeTimeType()).isWithdrawalFee()
|
||||||
&& ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
|
&& ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
|
||||||
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
.failWithCodeNoParameterAddedToErrorCode("charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
||||||
@@ -451,7 +456,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
this.active = newValue;
|
this.active = newValue;
|
||||||
}
|
}
|
||||||
// allow min and max cap to be only added to PERCENT_OF_AMOUNT for now
|
// allow min and max cap to be only added to PERCENT_OF_AMOUNT for now
|
||||||
if (isPercentageOfAmount()) {
|
if (isPercentageOfApprovedAmount()) {
|
||||||
final String minCapParamName = "minCap";
|
final String minCapParamName = "minCap";
|
||||||
if (command.isChangeInBigDecimalParameterNamed(minCapParamName, this.minCap)) {
|
if (command.isChangeInBigDecimalParameterNamed(minCapParamName, this.minCap)) {
|
||||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minCapParamName);
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minCapParamName);
|
||||||
@@ -466,11 +471,13 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
actualChanges.put("locale", localeAsInput);
|
actualChanges.put("locale", localeAsInput);
|
||||||
this.maxCap = newValue;
|
this.maxCap = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.penalty && ChargeTimeType.fromInt(this.chargeTime)
|
if (this.penalty && ChargeTimeType.fromInt(this.chargeTimeType)
|
||||||
.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(this.name); }
|
.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(this.name); }
|
||||||
if (!penalty && ChargeTimeType.fromInt(this.chargeTime).isOverdueInstallment()) { throw new ChargeMustBePenaltyException(name); }
|
if (!penalty
|
||||||
|
&& ChargeTimeType.fromInt(this.chargeTimeType).isOverdueInstallment()) { throw new ChargeMustBePenaltyException(name); }
|
||||||
|
|
||||||
if (command.isChangeInLongParameterNamed(ChargesApiConstants.glAccountIdParamName, getIncomeAccountId())) {
|
if (command.isChangeInLongParameterNamed(ChargesApiConstants.glAccountIdParamName, getIncomeAccountId())) {
|
||||||
final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName);
|
final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName);
|
||||||
@@ -495,7 +502,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public ChargeData toData() {
|
public ChargeData toData() {
|
||||||
|
|
||||||
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(this.chargeTime);
|
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(this.chargeTimeType);
|
||||||
final EnumOptionData chargeAppliesTo = ChargeEnumerations.chargeAppliesTo(this.chargeAppliesTo);
|
final EnumOptionData chargeAppliesTo = ChargeEnumerations.chargeAppliesTo(this.chargeAppliesTo);
|
||||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
|
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
|
||||||
final EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode);
|
final EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode);
|
||||||
@@ -519,15 +526,15 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMonthlyFee() {
|
public boolean isMonthlyFee() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).isMonthlyFee();
|
return ChargeTimeType.fromInt(this.chargeTimeType).isMonthlyFee();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAnnualFee() {
|
public boolean isAnnualFee() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).isAnnualFee();
|
return ChargeTimeType.fromInt(this.chargeTimeType).isAnnualFee();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOverdueInstallment() {
|
public boolean isOverdueInstallment() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).isOverdueInstallment();
|
return ChargeTimeType.fromInt(this.chargeTimeType).isOverdueInstallment();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonthDay getFeeOnMonthDay() {
|
public MonthDay getFeeOnMonthDay() {
|
||||||
@@ -561,4 +568,9 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
return incomeAccountId;
|
return incomeAccountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDisbursementCharge() {
|
||||||
|
return ChargeTimeType.fromInt(this.chargeTimeType).equals(ChargeTimeType.DISBURSEMENT)
|
||||||
|
|| ChargeTimeType.fromInt(this.chargeTimeType).equals(ChargeTimeType.TRANCHE_DISBURSEMENT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+12
-3
@@ -11,7 +11,8 @@ public enum ChargeCalculationType {
|
|||||||
FLAT(1, "chargeCalculationType.flat"), //
|
FLAT(1, "chargeCalculationType.flat"), //
|
||||||
PERCENT_OF_AMOUNT(2, "chargeCalculationType.percent.of.amount"), //
|
PERCENT_OF_AMOUNT(2, "chargeCalculationType.percent.of.amount"), //
|
||||||
PERCENT_OF_AMOUNT_AND_INTEREST(3, "chargeCalculationType.percent.of.amount.and.interest"), //
|
PERCENT_OF_AMOUNT_AND_INTEREST(3, "chargeCalculationType.percent.of.amount.and.interest"), //
|
||||||
PERCENT_OF_INTEREST(4, "chargeCalculationType.percent.of.interest");
|
PERCENT_OF_INTEREST(4, "chargeCalculationType.percent.of.interest"),
|
||||||
|
PERCENT_OF_DISBURSEMENT_AMOUNT(5,"chargeCalculationType.percent.of.disbursement.amount");
|
||||||
|
|
||||||
private final Integer value;
|
private final Integer value;
|
||||||
private final String code;
|
private final String code;
|
||||||
@@ -31,7 +32,8 @@ public enum ChargeCalculationType {
|
|||||||
|
|
||||||
public static Object[] validValuesForLoan() {
|
public static Object[] validValuesForLoan() {
|
||||||
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_AMOUNT.getValue(),
|
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_AMOUNT.getValue(),
|
||||||
ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue(), ChargeCalculationType.PERCENT_OF_INTEREST.getValue() };
|
ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue(), ChargeCalculationType.PERCENT_OF_INTEREST.getValue(),
|
||||||
|
ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue()};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] validValuesForSavings() {
|
public static Object[] validValuesForSavings() {
|
||||||
@@ -57,6 +59,9 @@ public enum ChargeCalculationType {
|
|||||||
case 4:
|
case 4:
|
||||||
chargeCalculationType = PERCENT_OF_INTEREST;
|
chargeCalculationType = PERCENT_OF_INTEREST;
|
||||||
break;
|
break;
|
||||||
|
case 5:
|
||||||
|
chargeCalculationType = PERCENT_OF_DISBURSEMENT_AMOUNT;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return chargeCalculationType;
|
return chargeCalculationType;
|
||||||
}
|
}
|
||||||
@@ -86,6 +91,10 @@ public enum ChargeCalculationType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPercentageBased() {
|
public boolean isPercentageBased() {
|
||||||
return isPercentageOfAmount() || isPercentageOfAmountAndInterest() || isPercentageOfInterest();
|
return isPercentageOfAmount() || isPercentageOfAmountAndInterest() || isPercentageOfInterest() || isPercentageOfDisbursementAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPercentageOfDisbursementAmount(){
|
||||||
|
return this.value.equals(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+12
-7
@@ -10,18 +10,16 @@ public enum ChargeTimeType {
|
|||||||
INVALID(0, "chargeTimeType.invalid"), //
|
INVALID(0, "chargeTimeType.invalid"), //
|
||||||
DISBURSEMENT(1, "chargeTimeType.disbursement"), // only for loan charges
|
DISBURSEMENT(1, "chargeTimeType.disbursement"), // only for loan charges
|
||||||
SPECIFIED_DUE_DATE(2, "chargeTimeType.specifiedDueDate"), // for loan and
|
SPECIFIED_DUE_DATE(2, "chargeTimeType.specifiedDueDate"), // for loan and
|
||||||
// savings charges
|
|
||||||
SAVINGS_ACTIVATION(3, "chargeTimeType.savingsActivation"), // only for
|
SAVINGS_ACTIVATION(3, "chargeTimeType.savingsActivation"), // only for
|
||||||
// savings
|
|
||||||
SAVINGS_CLOSURE(4, "chargeTimeType.savingsClosure"), // only for savings
|
SAVINGS_CLOSURE(4, "chargeTimeType.savingsClosure"), // only for savings
|
||||||
WITHDRAWAL_FEE(5, "chargeTimeType.withdrawalFee"), // only for savings
|
WITHDRAWAL_FEE(5, "chargeTimeType.withdrawalFee"), // only for savings
|
||||||
ANNUAL_FEE(6, "chargeTimeType.annualFee"), // only for savings
|
ANNUAL_FEE(6, "chargeTimeType.annualFee"), // only for savings
|
||||||
MONTHLY_FEE(7, "chargeTimeType.monthlyFee"), // only for savings
|
MONTHLY_FEE(7, "chargeTimeType.monthlyFee"), // only for savings
|
||||||
INSTALMENT_FEE(8, "chargeTimeType.instalmentFee"), // only for loan charges
|
INSTALMENT_FEE(8, "chargeTimeType.instalmentFee"), // only for loan charges
|
||||||
OVERDUE_INSTALLMENT(9, "chargeTimeType.overdueInstallment"), // only for
|
OVERDUE_INSTALLMENT(9, "chargeTimeType.overdueInstallment"), // only for
|
||||||
// loan charges
|
OVERDRAFT_FEE(10, "chargeTimeType.overdraftFee"),// only for savings
|
||||||
OVERDRAFT_FEE(10, "chargeTimeType.overdraftFee"), // only for savings
|
WEEKLY_FEE(11, "chargeTimeType.weeklyFee"), // only for savings
|
||||||
WEEKLY_FEE(11, "chargeTimeType.weeklyFee"); // only for savings
|
TRANCHE_DISBURSEMENT(12,"chargeTimeType.tranchedisbursement"); // only for loan
|
||||||
|
|
||||||
private final Integer value;
|
private final Integer value;
|
||||||
private final String code;
|
private final String code;
|
||||||
@@ -41,7 +39,7 @@ public enum ChargeTimeType {
|
|||||||
|
|
||||||
public static Object[] validLoanValues() {
|
public static Object[] validLoanValues() {
|
||||||
return new Integer[] { ChargeTimeType.DISBURSEMENT.getValue(), ChargeTimeType.SPECIFIED_DUE_DATE.getValue(),
|
return new Integer[] { ChargeTimeType.DISBURSEMENT.getValue(), ChargeTimeType.SPECIFIED_DUE_DATE.getValue(),
|
||||||
ChargeTimeType.INSTALMENT_FEE.getValue(), ChargeTimeType.OVERDUE_INSTALLMENT.getValue() };
|
ChargeTimeType.INSTALMENT_FEE.getValue(), ChargeTimeType.OVERDUE_INSTALLMENT.getValue(), ChargeTimeType.TRANCHE_DISBURSEMENT.getValue() };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] validLoanChargeValues() {
|
public static Object[] validLoanChargeValues() {
|
||||||
@@ -96,6 +94,9 @@ public enum ChargeTimeType {
|
|||||||
case 11:
|
case 11:
|
||||||
chargeTimeType = WEEKLY_FEE;
|
chargeTimeType = WEEKLY_FEE;
|
||||||
break;
|
break;
|
||||||
|
case 12:
|
||||||
|
chargeTimeType = TRANCHE_DISBURSEMENT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
chargeTimeType = INVALID;
|
chargeTimeType = INVALID;
|
||||||
break;
|
break;
|
||||||
@@ -145,7 +146,7 @@ public enum ChargeTimeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowedLoanChargeTime() {
|
public boolean isAllowedLoanChargeTime() {
|
||||||
return isTimeOfDisbursement() || isOnSpecifiedDueDate() || isInstalmentFee() || isOverdueInstallment();
|
return isTimeOfDisbursement() || isOnSpecifiedDueDate() || isInstalmentFee() || isOverdueInstallment() || isTrancheDisbursement();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowedClientChargeTime() {
|
public boolean isAllowedClientChargeTime() {
|
||||||
@@ -161,4 +162,8 @@ public enum ChargeTimeType {
|
|||||||
return this.value.equals(ChargeTimeType.OVERDRAFT_FEE.getValue());
|
return this.value.equals(ChargeTimeType.OVERDRAFT_FEE.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isTrancheDisbursement(){
|
||||||
|
return this.value.equals(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -263,7 +263,7 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
|||||||
if (this.fromApiJsonHelper.parameterExists("chargeCalculationType", element)) {
|
if (this.fromApiJsonHelper.parameterExists("chargeCalculationType", element)) {
|
||||||
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", element,
|
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", element,
|
||||||
Locale.getDefault());
|
Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull().inMinMaxRange(1, 4);
|
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull().inMinMaxRange(1, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists("chargePaymentMode", element)) {
|
if (this.fromApiJsonHelper.parameterExists("chargePaymentMode", element)) {
|
||||||
|
|||||||
-2
@@ -26,9 +26,7 @@ public interface ChargeDropdownReadPlatformService {
|
|||||||
List<EnumOptionData> retrieveSavingsCalculationTypes();
|
List<EnumOptionData> retrieveSavingsCalculationTypes();
|
||||||
|
|
||||||
List<EnumOptionData> retrieveSavingsCollectionTimeTypes();
|
List<EnumOptionData> retrieveSavingsCollectionTimeTypes();
|
||||||
|
|
||||||
List<EnumOptionData> retrieveClientCalculationTypes();
|
List<EnumOptionData> retrieveClientCalculationTypes();
|
||||||
|
|
||||||
List<EnumOptionData> retrieveClientCollectionTimeTypes();
|
List<EnumOptionData> retrieveClientCollectionTimeTypes();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -16,6 +16,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.*;
|
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.*;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -27,7 +28,8 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
|||||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
|
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
|
||||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT),
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT),
|
||||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
|
||||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST));
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST),
|
||||||
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -64,13 +66,15 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
|||||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
|
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
|
||||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT),
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT),
|
||||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
|
||||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST));
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST),
|
||||||
|
chargeCalculationType(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<EnumOptionData> retrieveLoanCollectionTimeTypes() {
|
public List<EnumOptionData> retrieveLoanCollectionTimeTypes() {
|
||||||
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE),
|
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE),
|
||||||
chargeTimeType(ChargeTimeType.INSTALMENT_FEE), chargeTimeType(ChargeTimeType.OVERDUE_INSTALLMENT));
|
chargeTimeType(ChargeTimeType.INSTALMENT_FEE), chargeTimeType(ChargeTimeType.OVERDUE_INSTALLMENT),
|
||||||
|
chargeTimeType(ChargeTimeType.TRANCHE_DISBURSEMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+9
-1
@@ -64,6 +64,10 @@ public class ChargeEnumerations {
|
|||||||
optionData = new EnumOptionData(ChargeTimeType.OVERDRAFT_FEE.getValue().longValue(), ChargeTimeType.OVERDRAFT_FEE.getCode(),
|
optionData = new EnumOptionData(ChargeTimeType.OVERDRAFT_FEE.getValue().longValue(), ChargeTimeType.OVERDRAFT_FEE.getCode(),
|
||||||
"Overdraft Fee");
|
"Overdraft Fee");
|
||||||
break;
|
break;
|
||||||
|
case TRANCHE_DISBURSEMENT:
|
||||||
|
optionData = new EnumOptionData(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue().longValue(),
|
||||||
|
ChargeTimeType.TRANCHE_DISBURSEMENT.getCode(), "Tranche Disbursement");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
optionData = new EnumOptionData(ChargeTimeType.INVALID.getValue().longValue(), ChargeTimeType.INVALID.getCode(), "Invalid");
|
optionData = new EnumOptionData(ChargeTimeType.INVALID.getValue().longValue(), ChargeTimeType.INVALID.getCode(), "Invalid");
|
||||||
break;
|
break;
|
||||||
@@ -109,7 +113,7 @@ public class ChargeEnumerations {
|
|||||||
break;
|
break;
|
||||||
case PERCENT_OF_AMOUNT:
|
case PERCENT_OF_AMOUNT:
|
||||||
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue().longValue(),
|
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue().longValue(),
|
||||||
ChargeCalculationType.PERCENT_OF_AMOUNT.getCode(), "% Amount");
|
ChargeCalculationType.PERCENT_OF_AMOUNT.getCode(), "% Approved Amount");
|
||||||
break;
|
break;
|
||||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||||
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue().longValue(),
|
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue().longValue(),
|
||||||
@@ -119,6 +123,10 @@ public class ChargeEnumerations {
|
|||||||
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_INTEREST.getValue().longValue(),
|
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_INTEREST.getValue().longValue(),
|
||||||
ChargeCalculationType.PERCENT_OF_INTEREST.getCode(), "% Interest");
|
ChargeCalculationType.PERCENT_OF_INTEREST.getCode(), "% Interest");
|
||||||
break;
|
break;
|
||||||
|
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||||
|
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue().longValue(),
|
||||||
|
ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getCode(), "% Disbursement Amount");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
optionData = new EnumOptionData(ChargeCalculationType.INVALID.getValue().longValue(),
|
optionData = new EnumOptionData(ChargeCalculationType.INVALID.getValue().longValue(),
|
||||||
ChargeCalculationType.INVALID.getCode(), "Invalid");
|
ChargeCalculationType.INVALID.getCode(), "Invalid");
|
||||||
|
|||||||
+21
-17
@@ -8,8 +8,8 @@ package org.mifosplatform.portfolio.charge.service;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -34,6 +34,7 @@ import org.springframework.cache.annotation.Cacheable;
|
|||||||
import org.springframework.dao.EmptyResultDataAccessException;
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +50,7 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
private final DropdownReadPlatformService dropdownReadPlatformService;
|
private final DropdownReadPlatformService dropdownReadPlatformService;
|
||||||
private final MifosEntityAccessUtil mifosEntityAccessUtil;
|
private final MifosEntityAccessUtil mifosEntityAccessUtil;
|
||||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||||
|
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ChargeReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService,
|
public ChargeReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService,
|
||||||
@@ -61,6 +63,7 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
||||||
this.mifosEntityAccessUtil = mifosEntityAccessUtil;
|
this.mifosEntityAccessUtil = mifosEntityAccessUtil;
|
||||||
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
||||||
|
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -172,14 +175,15 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
public Collection<ChargeData> retrieveLoanAccountApplicableCharges(final Long loanId, ChargeTimeType[] excludeChargeTimes) {
|
public Collection<ChargeData> retrieveLoanAccountApplicableCharges(final Long loanId, ChargeTimeType[] excludeChargeTimes) {
|
||||||
final ChargeMapper rm = new ChargeMapper();
|
final ChargeMapper rm = new ChargeMapper();
|
||||||
StringBuilder excludeClause = new StringBuilder("");
|
StringBuilder excludeClause = new StringBuilder("");
|
||||||
Object[] params = new Object[] { loanId, ChargeAppliesTo.LOAN.getValue() };
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
params = processChargeExclusionsForLoans(excludeChargeTimes, excludeClause, params);
|
paramMap.put("loanId", loanId);
|
||||||
String sql = "select " + rm.chargeSchema() + " join m_loan la on la.currency_code = c.currency_code" + " where la.id=?"
|
paramMap.put("chargeAppliesTo", ChargeAppliesTo.LOAN.getValue());
|
||||||
+ " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " ";
|
processChargeExclusionsForLoans(excludeChargeTimes, excludeClause);
|
||||||
|
String sql = "select " + rm.chargeSchema() + " join m_loan la on la.currency_code = c.currency_code" + " where la.id=:loanId"
|
||||||
|
+ " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=:chargeAppliesTo" + excludeClause + " ";
|
||||||
sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled();
|
sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled();
|
||||||
sql += " order by c.name ";
|
sql += " order by c.name ";
|
||||||
|
return this.namedParameterJdbcTemplate.query(sql, paramMap, rm);
|
||||||
return this.jdbcTemplate.query(sql, rm, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,9 +192,8 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
* @param params
|
* @param params
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Object[] processChargeExclusionsForLoans(ChargeTimeType[] excludeChargeTimes, StringBuilder excludeClause, Object[] params) {
|
private void processChargeExclusionsForLoans(ChargeTimeType[] excludeChargeTimes, StringBuilder excludeClause) {
|
||||||
if (excludeChargeTimes != null && excludeChargeTimes.length > 0) {
|
if (excludeChargeTimes != null && excludeChargeTimes.length > 0) {
|
||||||
excludeClause = excludeClause.append(" and c.charge_time_enum not in(?) ");
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = 0; i < excludeChargeTimes.length; i++) {
|
for (int i = 0; i < excludeChargeTimes.length; i++) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
@@ -198,24 +201,25 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
}
|
}
|
||||||
sb.append(excludeChargeTimes[i].getValue());
|
sb.append(excludeChargeTimes[i].getValue());
|
||||||
}
|
}
|
||||||
params = Arrays.copyOf(params, params.length + 1);
|
excludeClause = excludeClause.append(" and c.charge_time_enum not in(" + sb.toString() + ") ");
|
||||||
params[params.length - 1] = sb.toString();
|
|
||||||
}
|
}
|
||||||
return params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ChargeData> retrieveLoanProductApplicableCharges(final Long loanProductId, ChargeTimeType[] excludeChargeTimes) {
|
public Collection<ChargeData> retrieveLoanProductApplicableCharges(final Long loanProductId, ChargeTimeType[] excludeChargeTimes) {
|
||||||
final ChargeMapper rm = new ChargeMapper();
|
final ChargeMapper rm = new ChargeMapper();
|
||||||
StringBuilder excludeClause = new StringBuilder("");
|
StringBuilder excludeClause = new StringBuilder("");
|
||||||
Object[] params = new Object[] { loanProductId, ChargeAppliesTo.LOAN.getValue() };
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
params = processChargeExclusionsForLoans(excludeChargeTimes, excludeClause, params);
|
paramMap.put("productId", loanProductId);
|
||||||
String sql = "select " + rm.chargeSchema() + " join m_product_loan lp on lp.currency_code = c.currency_code" + " where lp.id=?"
|
paramMap.put("chargeAppliesTo", ChargeAppliesTo.LOAN.getValue());
|
||||||
+ " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " ";
|
processChargeExclusionsForLoans(excludeChargeTimes, excludeClause);
|
||||||
|
String sql = "select " + rm.chargeSchema() + " join m_product_loan lp on lp.currency_code = c.currency_code"
|
||||||
|
+ " where lp.id=:productId" + " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=:chargeAppliesTo"
|
||||||
|
+ excludeClause + " ";
|
||||||
sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled();
|
sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled();
|
||||||
sql += " order by c.name ";
|
sql += " order by c.name ";
|
||||||
|
|
||||||
return this.jdbcTemplate.query(sql, rm, params);
|
return this.namedParameterJdbcTemplate.query(sql, paramMap, rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -102,7 +102,7 @@ public class ClientCharge extends AbstractPersistable<Long> {
|
|||||||
this.client = client;
|
this.client = client;
|
||||||
this.charge = charge;
|
this.charge = charge;
|
||||||
this.penaltyCharge = charge.isPenalty();
|
this.penaltyCharge = charge.isPenalty();
|
||||||
this.chargeTime = charge.getChargeTime();
|
this.chargeTime = charge.getChargeTimeType();
|
||||||
this.dueDate = (dueDate == null) ? null : dueDate.toDate();
|
this.dueDate = (dueDate == null) ? null : dueDate.toDate();
|
||||||
this.chargeCalculation = charge.getChargeCalculation();
|
this.chargeCalculation = charge.getChargeCalculation();
|
||||||
|
|
||||||
|
|||||||
+2
@@ -15,7 +15,9 @@ public interface LoanApiConstants {
|
|||||||
public static final String updatedDisbursementDateParameterName = "updatedExpectedDisbursementDate";
|
public static final String updatedDisbursementDateParameterName = "updatedExpectedDisbursementDate";
|
||||||
public static final String updatedDisbursementPrincipalParameterName = "updatedPrincipal";
|
public static final String updatedDisbursementPrincipalParameterName = "updatedPrincipal";
|
||||||
public static final String disbursementIdParameterName = "id";
|
public static final String disbursementIdParameterName = "id";
|
||||||
|
public static final String loanChargeIdParameterName = "loanChargeId";
|
||||||
public static final String principalDisbursedParameterName = "transactionAmount";
|
public static final String principalDisbursedParameterName = "transactionAmount";
|
||||||
|
public static final String chargesParameterName = "charges" ;
|
||||||
|
|
||||||
public static final String approvedLoanAmountParameterName = "approvedLoanAmount";
|
public static final String approvedLoanAmountParameterName = "approvedLoanAmount";
|
||||||
public static final String approvedOnDateParameterName = "approvedOnDate";
|
public static final String approvedOnDateParameterName = "approvedOnDate";
|
||||||
|
|||||||
+8
-4
@@ -405,10 +405,9 @@ public class LoansApiResource {
|
|||||||
|
|
||||||
if (associationParameters.contains("repaymentSchedule")) {
|
if (associationParameters.contains("repaymentSchedule")) {
|
||||||
mandatoryResponseParameters.add("repaymentSchedule");
|
mandatoryResponseParameters.add("repaymentSchedule");
|
||||||
|
|
||||||
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData();
|
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData();
|
||||||
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData,
|
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData,
|
||||||
disbursementData, loanBasicDetails.isInterestRecalculationEnabled());
|
disbursementData, loanBasicDetails.isInterestRecalculationEnabled(), loanBasicDetails.getTotalPaidFeeCharges());
|
||||||
|
|
||||||
if (associationParameters.contains("futureSchedule") && loanBasicDetails.isInterestRecalculationEnabled()) {
|
if (associationParameters.contains("futureSchedule") && loanBasicDetails.isInterestRecalculationEnabled()) {
|
||||||
mandatoryResponseParameters.add("futureSchedule");
|
mandatoryResponseParameters.add("futureSchedule");
|
||||||
@@ -494,8 +493,13 @@ public class LoansApiResource {
|
|||||||
|
|
||||||
fundOptions = this.fundReadPlatformService.retrieveAllFunds();
|
fundOptions = this.fundReadPlatformService.retrieveAllFunds();
|
||||||
repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies();
|
repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies();
|
||||||
chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId,
|
if(product.getMultiDisburseLoan()){
|
||||||
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT });
|
chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId,
|
||||||
|
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT });
|
||||||
|
}else{
|
||||||
|
chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId,
|
||||||
|
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT });
|
||||||
|
}
|
||||||
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
|
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
|
||||||
|
|
||||||
allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(loanBasicDetails.officeId(),
|
allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(loanBasicDetails.officeId(),
|
||||||
|
|||||||
+9
-1
@@ -19,13 +19,17 @@ public class DisbursementData implements Comparable<DisbursementData> {
|
|||||||
private final LocalDate expectedDisbursementDate;
|
private final LocalDate expectedDisbursementDate;
|
||||||
private final LocalDate actualDisbursementDate;
|
private final LocalDate actualDisbursementDate;
|
||||||
private final BigDecimal principal;
|
private final BigDecimal principal;
|
||||||
|
private final String loanChargeId;
|
||||||
|
private final BigDecimal chargeAmount;
|
||||||
|
|
||||||
public DisbursementData(Long id, final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
|
public DisbursementData(Long id, final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
|
||||||
final BigDecimal principalDisbursed) {
|
final BigDecimal principalDisbursed, final String loanChargeId, BigDecimal chargeAmount) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.expectedDisbursementDate = expectedDisbursementDate;
|
this.expectedDisbursementDate = expectedDisbursementDate;
|
||||||
this.actualDisbursementDate = actualDisbursementDate;
|
this.actualDisbursementDate = actualDisbursementDate;
|
||||||
this.principal = principalDisbursed;
|
this.principal = principalDisbursed;
|
||||||
|
this.loanChargeId = loanChargeId;
|
||||||
|
this.chargeAmount = chargeAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate disbursementDate() {
|
public LocalDate disbursementDate() {
|
||||||
@@ -40,6 +44,10 @@ public class DisbursementData implements Comparable<DisbursementData> {
|
|||||||
return this.principal;
|
return this.principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getChargeAmount(){
|
||||||
|
return this.chargeAmount;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDisbursed() {
|
public boolean isDisbursed() {
|
||||||
return this.actualDisbursementDate != null;
|
return this.actualDisbursementDate != null;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -1387,4 +1387,12 @@ public class LoanAccountData {
|
|||||||
return LoanStatus.fromInt(this.status.id().intValue()).isActive();
|
return LoanStatus.fromInt(this.status.id().intValue()).isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMultiDisburseLoan() {
|
||||||
|
return multiDisburseLoan ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTotalPaidFeeCharges() {
|
||||||
|
if(this.summary != null) return this.summary.getTotalPaidFeeCharges() ;
|
||||||
|
return BigDecimal.ZERO ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
@@ -69,6 +69,7 @@ public class LoanChargeData {
|
|||||||
|
|
||||||
private BigDecimal amountUnrecognized;
|
private BigDecimal amountUnrecognized;
|
||||||
|
|
||||||
|
|
||||||
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
|
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
|
||||||
return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null, null,
|
return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null, null,
|
||||||
null, null, null);
|
null, null, null);
|
||||||
|
|||||||
+4
@@ -102,4 +102,8 @@ public class LoanSummaryData {
|
|||||||
public BigDecimal getTotalOutstanding() {
|
public BigDecimal getTotalOutstanding() {
|
||||||
return this.totalOutstanding;
|
return this.totalOutstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTotalPaidFeeCharges() {
|
||||||
|
return feeChargesPaid ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -62,6 +62,6 @@ public class RepaymentScheduleRelatedLoanData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DisbursementData disbursementData() {
|
public DisbursementData disbursementData() {
|
||||||
return new DisbursementData(null, this.expectedDisbursementDate, this.actualDisbursementDate, this.principal);
|
return new DisbursementData(null, this.expectedDisbursementDate, this.actualDisbursementDate, this.principal, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+445
-216
File diff suppressed because it is too large
Load Diff
+47
-19
@@ -7,7 +7,6 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -30,7 +29,6 @@ import javax.persistence.Temporal;
|
|||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
|
||||||
import org.hibernate.annotations.LazyCollection;
|
import org.hibernate.annotations.LazyCollection;
|
||||||
import org.hibernate.annotations.LazyCollectionOption;
|
import org.hibernate.annotations.LazyCollectionOption;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
@@ -121,6 +119,9 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
@OneToOne(mappedBy = "loancharge", cascade = CascadeType.ALL, optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
|
@OneToOne(mappedBy = "loancharge", cascade = CascadeType.ALL, optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||||
private LoanOverdueInstallmentCharge overdueInstallmentCharge;
|
private LoanOverdueInstallmentCharge overdueInstallmentCharge;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "loancharge", cascade = CascadeType.ALL, optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||||
|
private LoanTrancheDisbursementCharge loanTrancheDisbursementCharge;
|
||||||
|
|
||||||
public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
|
public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
|
||||||
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
|
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
|
||||||
return createNewFromJson(loan, chargeDefinition, command, dueDate);
|
return createNewFromJson(loan, chargeDefinition, command, dueDate);
|
||||||
@@ -144,8 +145,8 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
break;
|
break;
|
||||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||||
if (command.hasParameter("principal") && command.hasParameter("interest")) {
|
if (command.hasParameter("principal") && command.hasParameter("interest")) {
|
||||||
amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("principal")
|
amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("principal").add(
|
||||||
.add(command.bigDecimalValueOfParameterNamed("interest"));
|
command.bigDecimalValueOfParameterNamed("interest"));
|
||||||
} else {
|
} else {
|
||||||
amountPercentageAppliedTo = loan.getPrincpal().getAmount().add(loan.getTotalInterest());
|
amountPercentageAppliedTo = loan.getPrincpal().getAmount().add(loan.getTotalInterest());
|
||||||
}
|
}
|
||||||
@@ -162,7 +163,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal loanCharge = BigDecimal.ZERO;
|
BigDecimal loanCharge = BigDecimal.ZERO;
|
||||||
if (ChargeTimeType.fromInt(chargeDefinition.getChargeTime()).equals(ChargeTimeType.INSTALMENT_FEE)) {
|
if (ChargeTimeType.fromInt(chargeDefinition.getChargeTimeType()).equals(ChargeTimeType.INSTALMENT_FEE)) {
|
||||||
BigDecimal percentage = amount;
|
BigDecimal percentage = amount;
|
||||||
if (percentage == null) {
|
if (percentage == null) {
|
||||||
percentage = chargeDefinition.getAmount();
|
percentage = chargeDefinition.getAmount();
|
||||||
@@ -198,7 +199,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
this.minCap = chargeDefinition.getMinCap();
|
this.minCap = chargeDefinition.getMinCap();
|
||||||
this.maxCap = chargeDefinition.getMaxCap();
|
this.maxCap = chargeDefinition.getMaxCap();
|
||||||
|
|
||||||
this.chargeTime = chargeDefinition.getChargeTime();
|
this.chargeTime = chargeDefinition.getChargeTimeType();
|
||||||
if (chargeTime != null) {
|
if (chargeTime != null) {
|
||||||
this.chargeTime = chargeTime.getValue();
|
this.chargeTime = chargeTime.getValue();
|
||||||
}
|
}
|
||||||
@@ -267,6 +268,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
case PERCENT_OF_AMOUNT:
|
case PERCENT_OF_AMOUNT:
|
||||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||||
case PERCENT_OF_INTEREST:
|
case PERCENT_OF_INTEREST:
|
||||||
|
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||||
this.percentage = chargeAmount;
|
this.percentage = chargeAmount;
|
||||||
this.amountPercentageAppliedTo = amountPercentageAppliedTo;
|
this.amountPercentageAppliedTo = amountPercentageAppliedTo;
|
||||||
if (loanCharge.compareTo(BigDecimal.ZERO) == 0) {
|
if (loanCharge.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
@@ -291,6 +293,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
this.paid = true;
|
this.paid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFullyPaid() {
|
||||||
|
return this.paid;
|
||||||
|
}
|
||||||
|
|
||||||
public void resetToOriginal(final MonetaryCurrency currency) {
|
public void resetToOriginal(final MonetaryCurrency currency) {
|
||||||
this.amountPaid = BigDecimal.ZERO;
|
this.amountPaid = BigDecimal.ZERO;
|
||||||
this.amountWaived = BigDecimal.ZERO;
|
this.amountWaived = BigDecimal.ZERO;
|
||||||
@@ -335,6 +341,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmountPercentageAppliedTo() {
|
||||||
|
return this.amountPercentageAppliedTo;
|
||||||
|
}
|
||||||
|
|
||||||
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
||||||
return getAmount(currency).minus(getAmountWaived(currency)).minus(getAmountPaid(currency)).getAmount();
|
return getAmount(currency).minus(getAmountWaived(currency)).minus(getAmountPaid(currency)).getAmount();
|
||||||
}
|
}
|
||||||
@@ -366,6 +376,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
case PERCENT_OF_AMOUNT:
|
case PERCENT_OF_AMOUNT:
|
||||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||||
case PERCENT_OF_INTEREST:
|
case PERCENT_OF_INTEREST:
|
||||||
|
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||||
this.percentage = amount;
|
this.percentage = amount;
|
||||||
this.amountPercentageAppliedTo = loanPrincipal;
|
this.amountPercentageAppliedTo = loanPrincipal;
|
||||||
if (loanCharge.compareTo(BigDecimal.ZERO) == 0) {
|
if (loanCharge.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
@@ -395,6 +406,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
case PERCENT_OF_INTEREST:
|
case PERCENT_OF_INTEREST:
|
||||||
amountPercentageAppliedTo = this.loan.getTotalInterest();
|
amountPercentageAppliedTo = this.loan.getTotalInterest();
|
||||||
break;
|
break;
|
||||||
|
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||||
|
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = this.loanTrancheDisbursementCharge;
|
||||||
|
amountPercentageAppliedTo = loanTrancheDisbursementCharge.getloanDisbursementDetails().principal();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -423,6 +438,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
final String amountParamName = "amount";
|
final String amountParamName = "amount";
|
||||||
if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) {
|
if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) {
|
||||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName);
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||||
|
BigDecimal loanCharge = null;
|
||||||
actualChanges.put(amountParamName, newValue);
|
actualChanges.put(amountParamName, newValue);
|
||||||
actualChanges.put("locale", localeAsInput);
|
actualChanges.put("locale", localeAsInput);
|
||||||
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
|
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
|
||||||
@@ -439,9 +455,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
case PERCENT_OF_AMOUNT:
|
case PERCENT_OF_AMOUNT:
|
||||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||||
case PERCENT_OF_INTEREST:
|
case PERCENT_OF_INTEREST:
|
||||||
|
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||||
this.percentage = newValue;
|
this.percentage = newValue;
|
||||||
this.amountPercentageAppliedTo = amount;
|
this.amountPercentageAppliedTo = amount;
|
||||||
BigDecimal loanCharge = BigDecimal.ZERO;
|
loanCharge = BigDecimal.ZERO;
|
||||||
if (isInstalmentFee()) {
|
if (isInstalmentFee()) {
|
||||||
loanCharge = this.loan.calculatePerInstallmentChargeAmount(ChargeCalculationType.fromInt(this.chargeCalculation),
|
loanCharge = this.loan.calculatePerInstallmentChargeAmount(ChargeCalculationType.fromInt(this.chargeCalculation),
|
||||||
this.percentage);
|
this.percentage);
|
||||||
@@ -486,7 +503,8 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDueAtDisbursement() {
|
public boolean isDueAtDisbursement() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.DISBURSEMENT);
|
return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.DISBURSEMENT)
|
||||||
|
|| ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.TRANCHE_DISBURSEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSpecifiedDueDate() {
|
public boolean isSpecifiedDueDate() {
|
||||||
@@ -737,11 +755,12 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return new HashCodeBuilder(3, 5) //
|
return 1;
|
||||||
.append(getId()) //
|
/*
|
||||||
.append(this.charge.getId()) //
|
* return new HashCodeBuilder(3, 5) // .append(getId()) //
|
||||||
.append(this.amount).append(getDueLocalDate()) //
|
* .append(this.charge.getId()) //
|
||||||
.toHashCode();
|
* .append(this.amount).append(getDueLocalDate()) // .toHashCode();
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChargePaymentMode getChargePaymentMode() {
|
public ChargePaymentMode getChargePaymentMode() {
|
||||||
@@ -764,8 +783,9 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
public LoanInstallmentCharge getUnpaidInstallmentLoanCharge() {
|
public LoanInstallmentCharge getUnpaidInstallmentLoanCharge() {
|
||||||
LoanInstallmentCharge unpaidChargePerInstallment = null;
|
LoanInstallmentCharge unpaidChargePerInstallment = null;
|
||||||
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||||
if (loanChargePerInstallment.isPending() && (unpaidChargePerInstallment == null || unpaidChargePerInstallment
|
if (loanChargePerInstallment.isPending()
|
||||||
.getRepaymentInstallment().getDueDate().isAfter(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
|
&& (unpaidChargePerInstallment == null || unpaidChargePerInstallment.getRepaymentInstallment().getDueDate()
|
||||||
|
.isAfter(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
|
||||||
unpaidChargePerInstallment = loanChargePerInstallment;
|
unpaidChargePerInstallment = loanChargePerInstallment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -781,8 +801,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public LoanInstallmentCharge getInstallmentLoanCharge(final Integer installmentNumber) {
|
public LoanInstallmentCharge getInstallmentLoanCharge(final Integer installmentNumber) {
|
||||||
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||||
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber()
|
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber().intValue())) { return loanChargePerInstallment; }
|
||||||
.intValue())) { return loanChargePerInstallment; }
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -851,6 +870,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
this.overdueInstallmentCharge = overdueInstallmentCharge;
|
this.overdueInstallmentCharge = overdueInstallmentCharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateLoanTrancheDisbursementCharge(final LoanTrancheDisbursementCharge loanTrancheDisbursementCharge) {
|
||||||
|
this.loanTrancheDisbursementCharge = loanTrancheDisbursementCharge;
|
||||||
|
}
|
||||||
|
|
||||||
public void updateWaivedAmount(MonetaryCurrency currency) {
|
public void updateWaivedAmount(MonetaryCurrency currency) {
|
||||||
if (isInstalmentFee()) {
|
if (isInstalmentFee()) {
|
||||||
this.amountWaived = BigDecimal.ZERO;
|
this.amountWaived = BigDecimal.ZERO;
|
||||||
@@ -885,6 +908,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
return this.overdueInstallmentCharge;
|
return this.overdueInstallmentCharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanTrancheDisbursementCharge getTrancheDisbursementCharge() {
|
||||||
|
return this.loanTrancheDisbursementCharge;
|
||||||
|
}
|
||||||
|
|
||||||
public Money undoPaidOrPartiallyAmountBy(final Money incrementBy, final Integer installmentNumber, final Money feeAmount) {
|
public Money undoPaidOrPartiallyAmountBy(final Money incrementBy, final Integer installmentNumber, final Money feeAmount) {
|
||||||
Money processAmount = Money.zero(incrementBy.getCurrency());
|
Money processAmount = Money.zero(incrementBy.getCurrency());
|
||||||
if (isInstalmentFee()) {
|
if (isInstalmentFee()) {
|
||||||
@@ -922,8 +949,9 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
Money outstanding = Money.of(currency, loanChargePerInstallment.getAmountOutstanding());
|
Money outstanding = Money.of(currency, loanChargePerInstallment.getAmountOutstanding());
|
||||||
final boolean partiallyPaid = outstanding.isGreaterThanZero()
|
final boolean partiallyPaid = outstanding.isGreaterThanZero()
|
||||||
&& outstanding.isLessThan(loanChargePerInstallment.getAmount(currency));
|
&& outstanding.isLessThan(loanChargePerInstallment.getAmount(currency));
|
||||||
if ((partiallyPaid || loanChargePerInstallment.isPaid()) && (paidChargePerInstallment == null || paidChargePerInstallment
|
if ((partiallyPaid || loanChargePerInstallment.isPaid())
|
||||||
.getRepaymentInstallment().getDueDate().isBefore(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
|
&& (paidChargePerInstallment == null || paidChargePerInstallment.getRepaymentInstallment().getDueDate()
|
||||||
|
.isBefore(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
|
||||||
paidChargePerInstallment = loanChargePerInstallment;
|
paidChargePerInstallment = loanChargePerInstallment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
@@ -23,7 +24,7 @@ public class LoanChargePaidBy extends AbstractPersistable<Long> {
|
|||||||
@JoinColumn(name = "loan_transaction_id", nullable = false)
|
@JoinColumn(name = "loan_transaction_id", nullable = false)
|
||||||
private LoanTransaction loanTransaction;
|
private LoanTransaction loanTransaction;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(cascade= CascadeType.ALL)
|
||||||
@JoinColumn(name = "loan_charge_id", nullable = false)
|
@JoinColumn(name = "loan_charge_id", nullable = false)
|
||||||
private LoanCharge loanCharge;
|
private LoanCharge loanCharge;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -106,7 +106,7 @@ public class LoanDisbursementDetails extends AbstractPersistable<Long> {
|
|||||||
if (this.actualDisbursementDate != null) {
|
if (this.actualDisbursementDate != null) {
|
||||||
actualDisburseDate = new LocalDate(this.actualDisbursementDate);
|
actualDisburseDate = new LocalDate(this.actualDisbursementDate);
|
||||||
}
|
}
|
||||||
return new DisbursementData(getId(), expectedDisburseDate, actualDisburseDate, this.principal);
|
return new DisbursementData(getId(), expectedDisburseDate, actualDisburseDate, this.principal, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateActualDisbursementDate(Date actualDisbursementDate) {
|
public void updateActualDisbursementDate(Date actualDisbursementDate) {
|
||||||
|
|||||||
+3
-3
@@ -60,7 +60,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
|||||||
Money cumulative = Money.zero(monetaryCurrency);
|
Money cumulative = Money.zero(monetaryCurrency);
|
||||||
|
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
if (loanCharge.isFeeCharge()) {
|
if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) {
|
||||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||||
if (loanCharge.getChargeCalculation().isPercentageBased()) {
|
if (loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||||
BigDecimal amount = BigDecimal.ZERO;
|
BigDecimal amount = BigDecimal.ZERO;
|
||||||
@@ -108,7 +108,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
|||||||
Money cumulative = Money.zero(currency);
|
Money cumulative = Money.zero(currency);
|
||||||
|
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
if (loanCharge.isFeeCharge()) {
|
if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) {
|
||||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||||
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
||||||
if (loanChargePerInstallment != null) {
|
if (loanChargePerInstallment != null) {
|
||||||
@@ -129,7 +129,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
|||||||
Money cumulative = Money.zero(currency);
|
Money cumulative = Money.zero(currency);
|
||||||
|
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
if (loanCharge.isFeeCharge()) {
|
if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) {
|
||||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||||
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
||||||
if (loanChargePerInstallment != null) {
|
if (loanChargePerInstallment != null) {
|
||||||
|
|||||||
+9
-6
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
@@ -192,7 +193,7 @@ public final class LoanSummary {
|
|||||||
|
|
||||||
public void updateSummary(final MonetaryCurrency currency, final Money principal,
|
public void updateSummary(final MonetaryCurrency currency, final Money principal,
|
||||||
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LoanSummaryWrapper summaryWrapper,
|
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LoanSummaryWrapper summaryWrapper,
|
||||||
final Boolean disbursed) {
|
final Boolean disbursed, Set<LoanCharge> charges) {
|
||||||
|
|
||||||
this.totalPrincipalDisbursed = principal.getAmount();
|
this.totalPrincipalDisbursed = principal.getAmount();
|
||||||
this.totalPrincipalRepaid = summaryWrapper.calculateTotalPrincipalRepaid(repaymentScheduleInstallments, currency).getAmount();
|
this.totalPrincipalRepaid = summaryWrapper.calculateTotalPrincipalRepaid(repaymentScheduleInstallments, currency).getAmount();
|
||||||
@@ -214,13 +215,15 @@ public final class LoanSummary {
|
|||||||
this.totalFeeChargesDueAtDisbursement);
|
this.totalFeeChargesDueAtDisbursement);
|
||||||
this.totalFeeChargesCharged = totalFeeChargesCharged.getAmount();
|
this.totalFeeChargesCharged = totalFeeChargesCharged.getAmount();
|
||||||
|
|
||||||
Money totalFeeChargesRepaid = summaryWrapper.calculateTotalFeeChargesRepaid(repaymentScheduleInstallments, currency);
|
Money totalFeeChargesRepaidAtDisbursement = summaryWrapper.calculateTotalChargesRepaidAtDisbursement(charges,currency);
|
||||||
if (disbursed) {
|
this.totalFeeChargesRepaid = totalFeeChargesRepaidAtDisbursement.getAmount();
|
||||||
totalFeeChargesRepaid = totalFeeChargesRepaid.plus(this.totalFeeChargesDueAtDisbursement);
|
|
||||||
|
if(charges != null) {
|
||||||
|
this.totalFeeChargesWaived = summaryWrapper.calculateTotalFeeChargesWaived(charges, currency).getAmount();
|
||||||
|
}else {
|
||||||
|
this.totalFeeChargesWaived = BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
this.totalFeeChargesRepaid = totalFeeChargesRepaid.getAmount();
|
|
||||||
|
|
||||||
this.totalFeeChargesWaived = summaryWrapper.calculateTotalFeeChargesWaived(repaymentScheduleInstallments, currency).getAmount();
|
|
||||||
this.totalFeeChargesWrittenOff = summaryWrapper.calculateTotalFeeChargesWrittenOff(repaymentScheduleInstallments, currency)
|
this.totalFeeChargesWrittenOff = summaryWrapper.calculateTotalFeeChargesWrittenOff(repaymentScheduleInstallments, currency)
|
||||||
.getAmount();
|
.getAmount();
|
||||||
|
|
||||||
|
|||||||
+18
-3
@@ -6,6 +6,7 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||||
@@ -113,11 +114,13 @@ public final class LoanSummaryWrapper {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money calculateTotalFeeChargesWaived(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
public Money calculateTotalFeeChargesWaived(Set<LoanCharge> charges,
|
||||||
final MonetaryCurrency currency) {
|
final MonetaryCurrency currency) {
|
||||||
Money total = Money.zero(currency);
|
Money total = Money.zero(currency);
|
||||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
for (final LoanCharge charge : charges) {
|
||||||
total = total.plus(installment.getFeeChargesWaived(currency));
|
if(charge.isActive()){
|
||||||
|
total = total.plus(charge.getAmountWaived(currency));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
@@ -217,4 +220,16 @@ public final class LoanSummaryWrapper {
|
|||||||
|
|
||||||
return overdueSince;
|
return overdueSince;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Money calculateTotalChargesRepaidAtDisbursement(Set<LoanCharge> charges, MonetaryCurrency currency) {
|
||||||
|
Money total = Money.zero(currency);
|
||||||
|
if(charges == null) return total ;
|
||||||
|
for (final LoanCharge loanCharge : charges) {
|
||||||
|
if (!loanCharge.isPenaltyCharge() && loanCharge.getAmountPaid(currency).isGreaterThanZero()) {
|
||||||
|
total = total.plus(loanCharge.getAmountPaid(currency));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* 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.CascadeType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||||
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_loan_tranche_charges")
|
||||||
|
public class LoanTrancheCharge extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.ALL, optional = false)
|
||||||
|
@JoinColumn(name = "loan_id", nullable = false)
|
||||||
|
private Loan loan;
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.ALL, optional = false)
|
||||||
|
@JoinColumn(name = "charge_id", nullable = false)
|
||||||
|
private Charge charge;
|
||||||
|
|
||||||
|
LoanTrancheCharge() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LoanTrancheCharge(Charge chargeDefinition) {
|
||||||
|
this.charge = chargeDefinition ;
|
||||||
|
}
|
||||||
|
public LoanTrancheCharge(Charge charge, Loan loan) {
|
||||||
|
this.charge = charge;
|
||||||
|
this.loan = loan ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LoanTrancheCharge createLoanTrancheCharge(Charge chargeDefinition) {
|
||||||
|
return new LoanTrancheCharge(chargeDefinition) ;
|
||||||
|
}
|
||||||
|
public static LoanTrancheCharge createLoanTrancheChargeWithLoan(Charge chargeDefinition, Loan loan) {
|
||||||
|
return new LoanTrancheCharge(chargeDefinition, loan) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Charge getCharge() {
|
||||||
|
return charge ;
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* 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.CascadeType;
|
||||||
|
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_tranche_disbursement_charge")
|
||||||
|
public class LoanTrancheDisbursementCharge extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.ALL, optional = false)
|
||||||
|
@JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false)
|
||||||
|
private LoanCharge loancharge;
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.ALL, optional = false)
|
||||||
|
@JoinColumn(name="disbursement_detail_id", referencedColumnName = "id", nullable = false)
|
||||||
|
private LoanDisbursementDetails loanDisbursementDetails;
|
||||||
|
|
||||||
|
public LoanTrancheDisbursementCharge(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanTrancheDisbursementCharge(final LoanCharge loanCharge, final LoanDisbursementDetails loanDisbursementDetails){
|
||||||
|
this.loancharge = loanCharge;
|
||||||
|
this.loanDisbursementDetails = loanDisbursementDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanDisbursementDetails getloanDisbursementDetails(){
|
||||||
|
return this.loanDisbursementDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
@@ -327,6 +327,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
if (loanTransaction.isChargePayment()) {
|
if (loanTransaction.isChargePayment()) {
|
||||||
feeAmount = feeCharges;
|
feeAmount = feeCharges;
|
||||||
}
|
}
|
||||||
|
if(unpaidCharge == null) break ; //All are trache charges
|
||||||
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining, installmentNumber, feeAmount);
|
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining, installmentNumber, feeAmount);
|
||||||
if (!amountPaidTowardsCharge.isZero()) {
|
if (!amountPaidTowardsCharge.isZero()) {
|
||||||
Set<LoanChargePaidBy> chargesPaidBies = loanTransaction.getLoanChargesPaid();
|
Set<LoanChargePaidBy> chargesPaidBies = loanTransaction.getLoanChargesPaid();
|
||||||
|
|||||||
+8
-2
@@ -63,7 +63,13 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
|
|
||||||
// 3. setup variables for tracking important facts required for loan
|
// 3. setup variables for tracking important facts required for loan
|
||||||
// schedule generation.
|
// schedule generation.
|
||||||
Money principalDisbursed = loanApplicationTerms.getPrincipal();
|
Money principalDisbursed ;
|
||||||
|
|
||||||
|
if(loanApplicationTerms.isMultiDisburseLoan() && loanApplicationTerms.getApprovedPrincipal().isGreaterThanZero()) {
|
||||||
|
principalDisbursed = loanApplicationTerms.getApprovedPrincipal();
|
||||||
|
}else {
|
||||||
|
principalDisbursed = loanApplicationTerms.getPrincipal();
|
||||||
|
}
|
||||||
final MonetaryCurrency currency = principalDisbursed.getCurrency();
|
final MonetaryCurrency currency = principalDisbursed.getCurrency();
|
||||||
final int numberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
|
final int numberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
|
||||||
|
|
||||||
@@ -1644,7 +1650,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
Money cumulative = Money.zero(monetaryCurrency);
|
Money cumulative = Money.zero(monetaryCurrency);
|
||||||
|
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
if (loanCharge.isFeeCharge()) {
|
if (!loanCharge.isDueAtDisbursement() && loanCharge.isFeeCharge()) {
|
||||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||||
cumulative = calculateInstallmentCharge(principalInterestForThisPeriod, numberOfRepayments, cumulative, loanCharge);
|
cumulative = calculateInstallmentCharge(principalInterestForThisPeriod, numberOfRepayments, cumulative, loanCharge);
|
||||||
} else if (loanCharge.isOverdueInstallmentCharge()
|
} else if (loanCharge.isOverdueInstallmentCharge()
|
||||||
|
|||||||
+17
-11
@@ -148,6 +148,8 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
private final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy;
|
private final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy;
|
||||||
|
|
||||||
|
private Money approvedPrincipal = null ;
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
||||||
@@ -164,7 +166,7 @@ public final class LoanApplicationTerms {
|
|||||||
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
|
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
|
||||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar) {
|
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar, BigDecimal approvedAmount) {
|
||||||
|
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
||||||
@@ -176,7 +178,7 @@ public final class LoanApplicationTerms {
|
|||||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
|
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
|
||||||
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
|
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
|
||||||
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar);
|
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -191,7 +193,7 @@ public final class LoanApplicationTerms {
|
|||||||
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
||||||
final RecalculationFrequencyType compoundingFrequencyType,
|
final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod) {
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount) {
|
||||||
final Calendar loanCalendar = null;
|
final Calendar loanCalendar = null;
|
||||||
|
|
||||||
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
|
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
|
||||||
@@ -199,7 +201,7 @@ public final class LoanApplicationTerms {
|
|||||||
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
||||||
interestChargedFromDate, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType,
|
interestChargedFromDate, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType,
|
||||||
restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
||||||
loanPreClosureInterestCalculationStrategy, rescheduleStrategyMethod, loanCalendar);
|
loanPreClosureInterestCalculationStrategy, rescheduleStrategyMethod, loanCalendar, approvedAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -214,7 +216,7 @@ public final class LoanApplicationTerms {
|
|||||||
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
||||||
final RecalculationFrequencyType compoundingFrequencyType,
|
final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar) {
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -246,7 +248,7 @@ public final class LoanApplicationTerms {
|
|||||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||||
loanPreClosureInterestCalculationStrategy, loanCalendar);
|
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -259,7 +261,7 @@ public final class LoanApplicationTerms {
|
|||||||
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance compoundingCalendarInstance,
|
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance compoundingCalendarInstance,
|
||||||
final RecalculationFrequencyType compoundingFrequencyType, final BigDecimal principalThresholdForLastInstalment,
|
final RecalculationFrequencyType compoundingFrequencyType, final BigDecimal principalThresholdForLastInstalment,
|
||||||
final Integer installmentAmountInMultiplesOf,
|
final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy) {
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, BigDecimal approvedAmount) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -298,11 +300,11 @@ public final class LoanApplicationTerms {
|
|||||||
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
||||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||||
loanPreClosureInterestCalculationStrategy, loanCalendar);
|
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||||
final LoanApplicationTerms applicationTerms) {
|
final LoanApplicationTerms applicationTerms, BigDecimal approvedAmount) {
|
||||||
return new LoanApplicationTerms(applicationTerms.currency, applicationTerms.loanTermFrequency,
|
return new LoanApplicationTerms(applicationTerms.currency, applicationTerms.loanTermFrequency,
|
||||||
applicationTerms.loanTermPeriodFrequencyType, applicationTerms.numberOfRepayments, repaymentEvery,
|
applicationTerms.loanTermPeriodFrequencyType, applicationTerms.numberOfRepayments, repaymentEvery,
|
||||||
repaymentPeriodFrequencyType, null, null, applicationTerms.amortizationMethod, applicationTerms.interestMethod,
|
repaymentPeriodFrequencyType, null, null, applicationTerms.amortizationMethod, applicationTerms.interestMethod,
|
||||||
@@ -319,7 +321,7 @@ public final class LoanApplicationTerms {
|
|||||||
applicationTerms.recalculationFrequencyType, applicationTerms.compoundingCalendarInstance,
|
applicationTerms.recalculationFrequencyType, applicationTerms.compoundingCalendarInstance,
|
||||||
applicationTerms.compoundingFrequencyType, applicationTerms.principalThresholdForLastInstalment,
|
applicationTerms.compoundingFrequencyType, applicationTerms.principalThresholdForLastInstalment,
|
||||||
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy,
|
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy,
|
||||||
applicationTerms.loanCalendar);
|
applicationTerms.loanCalendar, approvedAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
@@ -339,7 +341,7 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
|
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
|
||||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar) {
|
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar, BigDecimal approvedAmount) {
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
this.loanTermFrequency = loanTermFrequency;
|
this.loanTermFrequency = loanTermFrequency;
|
||||||
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
||||||
@@ -388,6 +390,7 @@ public final class LoanApplicationTerms {
|
|||||||
this.preClosureInterestCalculationStrategy = preClosureInterestCalculationStrategy;
|
this.preClosureInterestCalculationStrategy = preClosureInterestCalculationStrategy;
|
||||||
|
|
||||||
this.loanCalendar = loanCalendar;
|
this.loanCalendar = loanCalendar;
|
||||||
|
this.approvedPrincipal = Money.of(principal.getCurrency(), approvedAmount) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||||
@@ -1043,6 +1046,9 @@ public final class LoanApplicationTerms {
|
|||||||
return this.principal;
|
return this.principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Money getApprovedPrincipal() {
|
||||||
|
return this.approvedPrincipal ;
|
||||||
|
}
|
||||||
public List<DisbursementData> getDisbursementDatas() {
|
public List<DisbursementData> getDisbursementDatas() {
|
||||||
return this.disbursementDatas;
|
return this.disbursementDatas;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -52,6 +52,7 @@ import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
|||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
|
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
@@ -303,7 +304,7 @@ public class LoanScheduleAssembler {
|
|||||||
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
||||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
|
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
|
||||||
restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar);
|
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
|
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
|
||||||
@@ -353,7 +354,7 @@ public class LoanScheduleAssembler {
|
|||||||
.isNotBlank((jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString()))) {
|
.isNotBlank((jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString()))) {
|
||||||
principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName).getAsBigDecimal();
|
principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName).getAsBigDecimal();
|
||||||
}
|
}
|
||||||
disbursementDatas.add(new DisbursementData(null, expectedDisbursementDate, null, principal));
|
disbursementDatas.add(new DisbursementData(null, expectedDisbursementDate, null, principal, null, null));
|
||||||
i++;
|
i++;
|
||||||
} while (i < disbursementDataArray.size());
|
} while (i < disbursementDataArray.size());
|
||||||
}
|
}
|
||||||
@@ -434,13 +435,13 @@ public class LoanScheduleAssembler {
|
|||||||
validateDisbursementDateIsOnNonWorkingDay(loanApplicationTerms.getExpectedDisbursementDate(), workingDays);
|
validateDisbursementDateIsOnNonWorkingDay(loanApplicationTerms.getExpectedDisbursementDate(), workingDays);
|
||||||
validateDisbursementDateIsOnHoliday(loanApplicationTerms.getExpectedDisbursementDate(), isHolidayEnabled, holidays);
|
validateDisbursementDateIsOnHoliday(loanApplicationTerms.getExpectedDisbursementDate(), isHolidayEnabled, holidays);
|
||||||
|
|
||||||
return assembleLoanScheduleFrom(loanApplicationTerms, isHolidayEnabled, holidays, workingDays, element);
|
return assembleLoanScheduleFrom(loanApplicationTerms, isHolidayEnabled, holidays, workingDays, element, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanScheduleModel assembleLoanScheduleFrom(final LoanApplicationTerms loanApplicationTerms, final boolean isHolidayEnabled,
|
public LoanScheduleModel assembleLoanScheduleFrom(final LoanApplicationTerms loanApplicationTerms, final boolean isHolidayEnabled,
|
||||||
final List<Holiday> holidays, final WorkingDays workingDays, final JsonElement element) {
|
final List<Holiday> holidays, final WorkingDays workingDays, final JsonElement element, Set<LoanDisbursementDetails> disbursementDetails) {
|
||||||
|
|
||||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element);
|
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element,disbursementDetails);
|
||||||
|
|
||||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -372,7 +372,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
waiveLoanCharges(loan, waiveLoanCharges);
|
waiveLoanCharges(loan, waiveLoanCharges);
|
||||||
|
|
||||||
// update the Loan summary
|
// update the Loan summary
|
||||||
loanSummary.updateSummary(currency, loan.getPrincpal(), repaymentScheduleInstallments, new LoanSummaryWrapper(), true);
|
loanSummary.updateSummary(currency, loan.getPrincpal(), repaymentScheduleInstallments, new LoanSummaryWrapper(), true, null);
|
||||||
|
|
||||||
// update the total number of schedule repayments
|
// update the total number of schedule repayments
|
||||||
loan.updateNumberOfRepayments(periods.size());
|
loan.updateNumberOfRepayments(periods.size());
|
||||||
|
|||||||
+10
-2
@@ -43,6 +43,7 @@ import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
|||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||||
@@ -63,6 +64,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateM
|
|||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
@@ -484,15 +486,21 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
LoanChargeData chargeData = new LoanChargeData(charge.getId(), charge.getDueLocalDate(), charge.amountOrPercentage());
|
LoanChargeData chargeData = new LoanChargeData(charge.getId(), charge.getDueLocalDate(), charge.amountOrPercentage());
|
||||||
chargesMap.put(charge.getId(), chargeData);
|
chargesMap.put(charge.getId(), chargeData);
|
||||||
}
|
}
|
||||||
|
Set<LoanDisbursementDetails> disbursementDetails = this.loanAssembler.fetchDisbursementData(command.parsedJson().getAsJsonObject());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores all charges which are passed in during modify loan
|
* Stores all charges which are passed in during modify loan
|
||||||
* application
|
* application
|
||||||
**/
|
**/
|
||||||
final Set<LoanCharge> possiblyModifedLoanCharges = this.loanChargeAssembler.fromParsedJson(command.parsedJson());
|
final Set<LoanCharge> possiblyModifedLoanCharges = this.loanChargeAssembler.fromParsedJson(command.parsedJson(),disbursementDetails);
|
||||||
/** Boolean determines if any charge has been modified **/
|
/** Boolean determines if any charge has been modified **/
|
||||||
boolean isChargeModified = false;
|
boolean isChargeModified = false;
|
||||||
|
|
||||||
|
Set<Charge> newTrancheChages = this.loanChargeAssembler.getNewLoanTrancheCharges(command.parsedJson()) ;
|
||||||
|
for (Charge charge : newTrancheChages) {
|
||||||
|
existingLoanApplication.addTrancheLoanCharge(charge) ;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there are any charges already present, which are now not
|
* If there are any charges already present, which are now not
|
||||||
* passed in as a part of the request, deem the charges as modified
|
* passed in as a part of the request, deem the charges as modified
|
||||||
@@ -872,7 +880,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
|
|
||||||
// If loan approved amount less than loan demanded amount, then need
|
// If loan approved amount less than loan demanded amount, then need
|
||||||
// to recompute the schedule
|
// to recompute the schedule
|
||||||
if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName)) {
|
if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName) || changes.containsKey("recalculateLoanSchedule")) {
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = loanAccountDomainService.buildScheduleGeneratorDTO(loan);
|
ScheduleGeneratorDTO scheduleGeneratorDTO = loanAccountDomainService.buildScheduleGeneratorDTO(loan);
|
||||||
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
|
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-24
@@ -172,8 +172,30 @@ public class LoanAssembler {
|
|||||||
if (loanPurposeId != null) {
|
if (loanPurposeId != null) {
|
||||||
loanPurpose = this.codeValueRepository.findOneWithNotFoundDetection(loanPurposeId);
|
loanPurpose = this.codeValueRepository.findOneWithNotFoundDetection(loanPurposeId);
|
||||||
}
|
}
|
||||||
|
Set<LoanDisbursementDetails> disbursementDetails = null;
|
||||||
|
BigDecimal fixedEmiAmount = null;
|
||||||
|
if (loanProduct.isMultiDisburseLoan() || loanProduct.canDefineInstallmentAmount()) {
|
||||||
|
fixedEmiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName, element);
|
||||||
|
}
|
||||||
|
BigDecimal maxOutstandingLoanBalance = null;
|
||||||
|
if (loanProduct.isMultiDisburseLoan()) {
|
||||||
|
disbursementDetails = fetchDisbursementData(element.getAsJsonObject());
|
||||||
|
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
|
||||||
|
maxOutstandingLoanBalance = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.maxOutstandingBalanceParameterName,
|
||||||
|
element, locale);
|
||||||
|
if (disbursementDetails.isEmpty()) {
|
||||||
|
final String errorMessage = "For this loan product, disbursement details must be provided";
|
||||||
|
throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disbursementDetails.size() > loanProduct.maxTrancheCount()) {
|
||||||
|
final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount();
|
||||||
|
throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage,
|
||||||
|
loanProduct.maxTrancheCount(), disbursementDetails.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
final Set<LoanCollateral> collateral = this.loanCollateralAssembler.fromParsedJson(element);
|
final Set<LoanCollateral> collateral = this.loanCollateralAssembler.fromParsedJson(element);
|
||||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element);
|
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element,disbursementDetails);
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
if (!loanProduct.hasCurrencyCodeOf(loanCharge.currencyCode())) {
|
if (!loanProduct.hasCurrencyCodeOf(loanCharge.currencyCode())) {
|
||||||
final String errorMessage = "Charge and Loan must have the same currency.";
|
final String errorMessage = "Charge and Loan must have the same currency.";
|
||||||
@@ -197,28 +219,7 @@ public class LoanAssembler {
|
|||||||
final String loanTypeParameterName = "loanType";
|
final String loanTypeParameterName = "loanType";
|
||||||
final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
|
final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
|
||||||
final EnumOptionData loanType = AccountEnumerations.loanType(loanTypeStr);
|
final EnumOptionData loanType = AccountEnumerations.loanType(loanTypeStr);
|
||||||
Set<LoanDisbursementDetails> disbursementDetails = null;
|
|
||||||
BigDecimal fixedEmiAmount = null;
|
|
||||||
if (loanProduct.isMultiDisburseLoan() || loanProduct.canDefineInstallmentAmount()) {
|
|
||||||
fixedEmiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName, element);
|
|
||||||
}
|
|
||||||
BigDecimal maxOutstandingLoanBalance = null;
|
|
||||||
if (loanProduct.isMultiDisburseLoan()) {
|
|
||||||
disbursementDetails = fetchDisbursementData(element.getAsJsonObject());
|
|
||||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
|
|
||||||
maxOutstandingLoanBalance = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.maxOutstandingBalanceParameterName,
|
|
||||||
element, locale);
|
|
||||||
if (disbursementDetails.isEmpty()) {
|
|
||||||
final String errorMessage = "For this loan product, disbursement details must be provided";
|
|
||||||
throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disbursementDetails.size() > loanProduct.maxTrancheCount()) {
|
|
||||||
final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount();
|
|
||||||
throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage,
|
|
||||||
loanProduct.maxTrancheCount(), disbursementDetails.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clientId != null) {
|
if (clientId != null) {
|
||||||
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||||
@@ -281,7 +282,7 @@ public class LoanAssembler {
|
|||||||
final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||||
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
|
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
|
||||||
final LoanScheduleModel loanScheduleModel = this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms,
|
final LoanScheduleModel loanScheduleModel = this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms,
|
||||||
isHolidayEnabled, holidays, workingDays, element);
|
isHolidayEnabled, holidays, workingDays, element,disbursementDetails);
|
||||||
loanApplication.loanApplicationSubmittal(currentUser, loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(),
|
loanApplication.loanApplicationSubmittal(currentUser, loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(),
|
||||||
submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay,
|
submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay,
|
||||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate);
|
recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate);
|
||||||
@@ -289,7 +290,7 @@ public class LoanAssembler {
|
|||||||
return loanApplication;
|
return loanApplication;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<LoanDisbursementDetails> fetchDisbursementData(final JsonObject command) {
|
public Set<LoanDisbursementDetails> fetchDisbursementData(final JsonObject command) {
|
||||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(command);
|
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(command);
|
||||||
final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(command);
|
final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(command);
|
||||||
Set<LoanDisbursementDetails> disbursementDatas = new HashSet<>();
|
Set<LoanDisbursementDetails> disbursementDatas = new HashSet<>();
|
||||||
|
|||||||
+138
-11
@@ -6,7 +6,9 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.service;
|
package org.mifosplatform.portfolio.loanaccount.service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -19,8 +21,15 @@ import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
|||||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTrancheCharge;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -34,21 +43,49 @@ public class LoanChargeAssembler {
|
|||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
private final ChargeRepositoryWrapper chargeRepository;
|
private final ChargeRepositoryWrapper chargeRepository;
|
||||||
private final LoanChargeRepository loanChargeRepository;
|
private final LoanChargeRepository loanChargeRepository;
|
||||||
|
private final LoanProductRepository loanProductRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanChargeAssembler(final FromJsonHelper fromApiJsonHelper, final ChargeRepositoryWrapper chargeRepository,
|
public LoanChargeAssembler(final FromJsonHelper fromApiJsonHelper, final ChargeRepositoryWrapper chargeRepository,
|
||||||
final LoanChargeRepository loanChargeRepository) {
|
final LoanChargeRepository loanChargeRepository, final LoanProductRepository loanProductRepository) {
|
||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
this.chargeRepository = chargeRepository;
|
this.chargeRepository = chargeRepository;
|
||||||
this.loanChargeRepository = loanChargeRepository;
|
this.loanChargeRepository = loanChargeRepository;
|
||||||
|
this.loanProductRepository = loanProductRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<LoanCharge> fromParsedJson(final JsonElement element) {
|
public Set<LoanCharge> fromParsedJson(final JsonElement element, Set<LoanDisbursementDetails> disbursementDetails) {
|
||||||
|
JsonArray jsonDisbursement = this.fromApiJsonHelper.extractJsonArrayNamed("disbursementData", element) ;
|
||||||
|
List<Long> disbursementChargeIds = new ArrayList<>();
|
||||||
|
|
||||||
|
if(jsonDisbursement != null && jsonDisbursement.size() > 0) {
|
||||||
|
for(int i = 0 ; i < jsonDisbursement.size(); i++) {
|
||||||
|
final JsonObject jsonObject = jsonDisbursement.get(i).getAsJsonObject();
|
||||||
|
if(jsonObject != null && jsonObject.getAsJsonPrimitive(LoanApiConstants.loanChargeIdParameterName) != null){
|
||||||
|
String chargeIds = jsonObject.getAsJsonPrimitive(LoanApiConstants.loanChargeIdParameterName).getAsString();
|
||||||
|
if(chargeIds != null) {
|
||||||
|
if (chargeIds.indexOf(",") != -1) {
|
||||||
|
String[] chargeId = chargeIds.split(",");
|
||||||
|
for (String loanChargeId : chargeId) {
|
||||||
|
disbursementChargeIds.add(Long.parseLong(loanChargeId));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
disbursementChargeIds.add(Long.parseLong(chargeIds)) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final Set<LoanCharge> loanCharges = new HashSet<>();
|
final Set<LoanCharge> loanCharges = new HashSet<>();
|
||||||
|
|
||||||
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
||||||
final Integer numberOfRepayments = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
|
final Integer numberOfRepayments = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
|
||||||
|
final Long productId = this.fromApiJsonHelper.extractLongNamed("productId", element);
|
||||||
|
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||||
|
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||||
|
final boolean isMultiDisbursal = loanProduct.isMultiDisburseLoan();
|
||||||
|
LocalDate expectedDisbursementDate = null;
|
||||||
|
|
||||||
if (element.isJsonObject()) {
|
if (element.isJsonObject()) {
|
||||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||||
@@ -92,17 +129,85 @@ public class LoanChargeAssembler {
|
|||||||
if (chargePaymentMode != null) {
|
if (chargePaymentMode != null) {
|
||||||
chargePaymentModeEnum = ChargePaymentMode.fromInt(chargePaymentMode);
|
chargePaymentModeEnum = ChargePaymentMode.fromInt(chargePaymentMode);
|
||||||
}
|
}
|
||||||
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, principal, amount, chargeTime,
|
if (!isMultiDisbursal) {
|
||||||
chargeCalculation, dueDate, chargePaymentModeEnum, numberOfRepayments);
|
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, principal, amount, chargeTime,
|
||||||
loanCharges.add(loanCharge);
|
chargeCalculation, dueDate, chargePaymentModeEnum, numberOfRepayments);
|
||||||
|
loanCharges.add(loanCharge);
|
||||||
|
}
|
||||||
|
if (topLevelJsonElement.has("disbursementData") && topLevelJsonElement.get("disbursementData").isJsonArray()) {
|
||||||
|
final JsonArray disbursementArray = topLevelJsonElement.get("disbursementData").getAsJsonArray();
|
||||||
|
JsonObject disbursementDataElement = disbursementArray.get(0).getAsJsonObject();
|
||||||
|
expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||||
|
LoanApiConstants.disbursementDateParameterName, disbursementDataElement, dateFormat, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((chargeDefinition.isPercentageOfDisbursementAmount() || chargeDefinition.isPercentageOfApprovedAmount() || chargeDefinition
|
||||||
|
.getChargeCalculation() == ChargeCalculationType.FLAT.getValue()) && disbursementDetails != null) {
|
||||||
|
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null;
|
||||||
|
for (LoanDisbursementDetails disbursementDetail : disbursementDetails) {
|
||||||
|
if (chargeDefinition.getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue()) {
|
||||||
|
if (chargeDefinition.isPercentageOfApprovedAmount()
|
||||||
|
&& disbursementDetail.expectedDisbursementDateAsLocalDate().equals(expectedDisbursementDate)) {
|
||||||
|
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, principal, amount,
|
||||||
|
chargeTime, chargeCalculation, dueDate, chargePaymentModeEnum, numberOfRepayments);
|
||||||
|
loanCharges.add(loanCharge);
|
||||||
|
loanTrancheDisbursementCharge = new LoanTrancheDisbursementCharge(loanCharge, disbursementDetail);
|
||||||
|
loanCharge.updateLoanTrancheDisbursementCharge(loanTrancheDisbursementCharge);
|
||||||
|
} else {
|
||||||
|
if (disbursementDetail.expectedDisbursementDateAsLocalDate().equals(expectedDisbursementDate)) {
|
||||||
|
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition,
|
||||||
|
disbursementDetail.principal(), amount, chargeTime, chargeCalculation,
|
||||||
|
disbursementDetail.expectedDisbursementDateAsLocalDate(), chargePaymentModeEnum,
|
||||||
|
numberOfRepayments);
|
||||||
|
loanCharges.add(loanCharge);
|
||||||
|
loanTrancheDisbursementCharge = new LoanTrancheDisbursementCharge(loanCharge,
|
||||||
|
disbursementDetail);
|
||||||
|
loanCharge.updateLoanTrancheDisbursementCharge(loanTrancheDisbursementCharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (chargeDefinition.getChargeTimeType() == ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()) {
|
||||||
|
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition,
|
||||||
|
disbursementDetail.principal(), amount, chargeTime, chargeCalculation,
|
||||||
|
disbursementDetail.expectedDisbursementDateAsLocalDate(), chargePaymentModeEnum,
|
||||||
|
numberOfRepayments);
|
||||||
|
loanCharges.add(loanCharge);
|
||||||
|
loanTrancheDisbursementCharge = new LoanTrancheDisbursementCharge(loanCharge, disbursementDetail);
|
||||||
|
loanCharge.updateLoanTrancheDisbursementCharge(loanTrancheDisbursementCharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null;
|
||||||
|
if (disbursementDetails != null) {
|
||||||
|
for (LoanDisbursementDetails disbursementDetail : disbursementDetails) {
|
||||||
|
if (!(disbursementDetail.expectedDisbursementDateAsLocalDate().isAfter(expectedDisbursementDate))) {
|
||||||
|
if (chargeDefinition.getChargeCalculation() == ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST
|
||||||
|
.getValue()
|
||||||
|
|| chargeDefinition.getChargeTimeType() == ChargeTimeType.SPECIFIED_DUE_DATE.getValue()
|
||||||
|
|| chargeDefinition.getChargeCalculation() == ChargeCalculationType.PERCENT_OF_INTEREST
|
||||||
|
.getValue()) {
|
||||||
|
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, principal,
|
||||||
|
amount, chargeTime, chargeCalculation, dueDate, chargePaymentModeEnum,
|
||||||
|
numberOfRepayments);
|
||||||
|
loanCharges.add(loanCharge);
|
||||||
|
loanTrancheDisbursementCharge = new LoanTrancheDisbursementCharge(loanCharge,
|
||||||
|
disbursementDetail);
|
||||||
|
loanCharge.updateLoanTrancheDisbursementCharge(loanTrancheDisbursementCharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
final Long loanChargeId = id;
|
final Long loanChargeId = id;
|
||||||
final LoanCharge loanCharge = this.loanChargeRepository.findOne(loanChargeId);
|
final LoanCharge loanCharge = this.loanChargeRepository.findOne(loanChargeId);
|
||||||
if (loanCharge == null) { throw new LoanChargeNotFoundException(loanChargeId); }
|
if(disbursementChargeIds.contains(loanChargeId) && loanCharge == null) {
|
||||||
|
//throw new LoanChargeNotFoundException(loanChargeId);
|
||||||
loanCharge.update(amount, dueDate, numberOfRepayments);
|
}
|
||||||
|
if(loanCharge != null) {
|
||||||
loanCharges.add(loanCharge);
|
loanCharge.update(amount, dueDate, numberOfRepayments);
|
||||||
|
loanCharges.add(loanCharge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,4 +215,26 @@ public class LoanChargeAssembler {
|
|||||||
|
|
||||||
return loanCharges;
|
return loanCharges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Charge> getNewLoanTrancheCharges(final JsonElement element) {
|
||||||
|
final Set<Charge> associatedChargesForLoan = new HashSet<>();
|
||||||
|
if (element.isJsonObject()) {
|
||||||
|
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||||
|
if (topLevelJsonElement.has("charges") && topLevelJsonElement.get("charges").isJsonArray()) {
|
||||||
|
final JsonArray array = topLevelJsonElement.get("charges").getAsJsonArray();
|
||||||
|
for (int i = 0; i < array.size(); i++) {
|
||||||
|
final JsonObject loanChargeElement = array.get(i).getAsJsonObject();
|
||||||
|
final Long id = this.fromApiJsonHelper.extractLongNamed("id", loanChargeElement);
|
||||||
|
final Long chargeId = this.fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
|
||||||
|
if (id == null) {
|
||||||
|
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
|
||||||
|
if (chargeDefinition.getChargeTimeType() == ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()) {
|
||||||
|
associatedChargesForLoan.add(chargeDefinition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return associatedChargesForLoan;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+10
-3
@@ -64,9 +64,11 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
+ "lc.charge_payment_mode_enum as chargePaymentMode, " + "lc.is_paid_derived as paid, " + "lc.waived as waied, "
|
+ "lc.charge_payment_mode_enum as chargePaymentMode, " + "lc.is_paid_derived as paid, " + "lc.waived as waied, "
|
||||||
+ "lc.min_cap as minCap, lc.max_cap as maxCap, " + "lc.charge_amount_or_percentage as amountOrPercentage, "
|
+ "lc.min_cap as minCap, lc.max_cap as maxCap, " + "lc.charge_amount_or_percentage as amountOrPercentage, "
|
||||||
+ "c.currency_code as currencyCode, oc.name as currencyName, "
|
+ "c.currency_code as currencyCode, oc.name as currencyName, "
|
||||||
|
+ "date(ifnull(dd.disbursedon_date,dd.expected_disburse_date)) as disbursementDate, "
|
||||||
+ "oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
+ "oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
||||||
+ "oc.internationalized_name_code as currencyNameCode from m_charge c "
|
+ "oc.internationalized_name_code as currencyNameCode from m_charge c "
|
||||||
+ "join m_organisation_currency oc on c.currency_code = oc.code " + "join m_loan_charge lc on lc.charge_id = c.id ";
|
+ "join m_organisation_currency oc on c.currency_code = oc.code " + "join m_loan_charge lc on lc.charge_id = c.id "
|
||||||
|
+ "left join m_loan_tranche_disbursement_charge dc on dc.loan_charge_id=lc.id left join m_loan_disbursement_detail dd on dd.id=dc.disbursement_detail_id ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -97,7 +99,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
final int chargeTime = rs.getInt("chargeTime");
|
final int chargeTime = rs.getInt("chargeTime");
|
||||||
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime);
|
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime);
|
||||||
|
|
||||||
final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
|
LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
|
||||||
|
|
||||||
final int chargeCalculation = rs.getInt("chargeCalculation");
|
final int chargeCalculation = rs.getInt("chargeCalculation");
|
||||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
||||||
@@ -110,6 +112,11 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
final BigDecimal minCap = rs.getBigDecimal("minCap");
|
final BigDecimal minCap = rs.getBigDecimal("minCap");
|
||||||
final BigDecimal maxCap = rs.getBigDecimal("maxCap");
|
final BigDecimal maxCap = rs.getBigDecimal("maxCap");
|
||||||
final BigDecimal amountOrPercentage = rs.getBigDecimal("amountOrPercentage");
|
final BigDecimal amountOrPercentage = rs.getBigDecimal("amountOrPercentage");
|
||||||
|
final LocalDate disbursementDate = JdbcSupport.getLocalDate(rs, "disbursementDate");
|
||||||
|
|
||||||
|
if (disbursementDate != null) {
|
||||||
|
dueAsOfDate = disbursementDate;
|
||||||
|
}
|
||||||
|
|
||||||
return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding,
|
return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding,
|
||||||
chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty, paymentMode, paid,
|
chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty, paymentMode, paid,
|
||||||
@@ -161,7 +168,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
final LoanChargeMapper rm = new LoanChargeMapper();
|
final LoanChargeMapper rm = new LoanChargeMapper();
|
||||||
|
|
||||||
final String sql = "select " + rm.schema() + " where lc.loan_id=? AND lc.is_active = 1"
|
final String sql = "select " + rm.schema() + " where lc.loan_id=? AND lc.is_active = 1"
|
||||||
+ " order by lc.charge_time_enum ASC, lc.due_for_collection_as_of_date ASC, lc.is_penalty ASC";
|
+ " order by ifnull(lc.due_for_collection_as_of_date,date(ifnull(dd.disbursedon_date,dd.expected_disburse_date))),lc.charge_time_enum ASC, lc.due_for_collection_as_of_date ASC, lc.is_penalty ASC";
|
||||||
|
|
||||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.loanaccount.service;
|
package org.mifosplatform.portfolio.loanaccount.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ public interface LoanReadPlatformService {
|
|||||||
LoanAccountData retrieveOne(Long loanId);
|
LoanAccountData retrieveOne(Long loanId);
|
||||||
|
|
||||||
LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData,
|
LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData,
|
||||||
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled);
|
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled, BigDecimal totalPaidFeeCharges);
|
||||||
|
|
||||||
Collection<LoanTransactionData> retrieveLoanTransactions(Long loanId);
|
Collection<LoanTransactionData> retrieveLoanTransactions(Long loanId);
|
||||||
|
|
||||||
|
|||||||
+46
-19
@@ -207,13 +207,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
@Override
|
@Override
|
||||||
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
|
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
|
||||||
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData,
|
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData,
|
||||||
boolean isInterestRecalculationEnabled) {
|
boolean isInterestRecalculationEnabled, BigDecimal totalPaidFeeCharges) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor(
|
final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor(
|
||||||
repaymentScheduleRelatedLoanData, disbursementData, isInterestRecalculationEnabled);
|
repaymentScheduleRelatedLoanData, disbursementData, isInterestRecalculationEnabled ,totalPaidFeeCharges);
|
||||||
final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment";
|
final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment";
|
||||||
|
|
||||||
return this.jdbcTemplate.query(sql, fullResultsetExtractor, new Object[] { loanId });
|
return this.jdbcTemplate.query(sql, fullResultsetExtractor, new Object[] { loanId });
|
||||||
@@ -954,9 +954,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
private LocalDate lastDueDate;
|
private LocalDate lastDueDate;
|
||||||
private BigDecimal outstandingLoanPrincipalBalance;
|
private BigDecimal outstandingLoanPrincipalBalance;
|
||||||
private boolean excludePastUndisbursed;
|
private boolean excludePastUndisbursed;
|
||||||
|
private BigDecimal totalPaidFeeCharges ;
|
||||||
public LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
|
public LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
|
||||||
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled) {
|
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled, BigDecimal totalPaidFeeCharges) {
|
||||||
this.currency = repaymentScheduleRelatedLoanData.getCurrency();
|
this.currency = repaymentScheduleRelatedLoanData.getCurrency();
|
||||||
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
||||||
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
||||||
@@ -964,6 +964,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
this.outstandingLoanPrincipalBalance = this.disbursement.amount();
|
this.outstandingLoanPrincipalBalance = this.disbursement.amount();
|
||||||
this.disbursementData = disbursementData;
|
this.disbursementData = disbursementData;
|
||||||
this.excludePastUndisbursed = isInterestRecalculationEnabled;
|
this.excludePastUndisbursed = isInterestRecalculationEnabled;
|
||||||
|
this.totalPaidFeeCharges = totalPaidFeeCharges ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
@@ -1014,7 +1015,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
// update totals with details of fees charged during disbursement
|
// update totals with details of fees charged during disbursement
|
||||||
totalFeeChargesCharged = totalFeeChargesCharged.plus(disbursementPeriod.feeChargesDue());
|
totalFeeChargesCharged = totalFeeChargesCharged.plus(disbursementPeriod.feeChargesDue());
|
||||||
totalRepaymentExpected = totalRepaymentExpected.plus(disbursementPeriod.feeChargesDue());
|
totalRepaymentExpected = totalRepaymentExpected.plus(disbursementPeriod.feeChargesDue());
|
||||||
totalRepayment = totalRepayment.plus(disbursementPeriod.feeChargesPaid());
|
totalRepayment = totalRepayment.plus(totalPaidFeeCharges);
|
||||||
totalOutstanding = totalOutstanding.plus(disbursementPeriod.feeChargesDue()).minus(disbursementPeriod.feeChargesPaid());
|
totalOutstanding = totalOutstanding.plus(disbursementPeriod.feeChargesDue()).minus(disbursementPeriod.feeChargesPaid());
|
||||||
|
|
||||||
Integer loanTermInDays = Integer.valueOf(0);
|
Integer loanTermInDays = Integer.valueOf(0);
|
||||||
@@ -1031,17 +1032,29 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
for (DisbursementData data : disbursementData) {
|
for (DisbursementData data : disbursementData) {
|
||||||
if (fromDate.equals(this.disbursement.disbursementDate()) && data.disbursementDate().equals(fromDate)) {
|
if (fromDate.equals(this.disbursement.disbursementDate()) && data.disbursementDate().equals(fromDate)) {
|
||||||
principal = principal.add(data.amount());
|
principal = principal.add(data.amount());
|
||||||
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
if(data.getChargeAmount() == null){
|
||||||
data.disbursementDate(), data.amount(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed());
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
periods.add(periodData);
|
data.disbursementDate(), data.amount(), BigDecimal.ZERO, data.isDisbursed());
|
||||||
|
periods.add(periodData);
|
||||||
|
}else{
|
||||||
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
|
data.disbursementDate(), data.amount(), data.getChargeAmount(), data.isDisbursed());
|
||||||
|
periods.add(periodData);
|
||||||
|
}
|
||||||
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||||
} else if (data.isDueForDisbursement(fromDate, dueDate)) {
|
} else if (data.isDueForDisbursement(fromDate, dueDate)) {
|
||||||
if (!excludePastUndisbursed
|
if (!excludePastUndisbursed
|
||||||
|| (excludePastUndisbursed && (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) {
|
|| (excludePastUndisbursed && (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) {
|
||||||
principal = principal.add(data.amount());
|
principal = principal.add(data.amount());
|
||||||
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
if(data.getChargeAmount() == null){
|
||||||
data.disbursementDate(), data.amount(), BigDecimal.ZERO, data.isDisbursed());
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
periods.add(periodData);
|
data.disbursementDate(), data.amount(), BigDecimal.ZERO, data.isDisbursed());
|
||||||
|
periods.add(periodData);
|
||||||
|
}else{
|
||||||
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
|
data.disbursementDate(), data.amount(), data.getChargeAmount(), data.isDisbursed());
|
||||||
|
periods.add(periodData);
|
||||||
|
}
|
||||||
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1329,8 +1342,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final Collection<CodeValueData> loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
|
final Collection<CodeValueData> loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
|
||||||
final Collection<CodeValueData> loanCollateralOptions = this.codeValueReadPlatformService
|
final Collection<CodeValueData> loanCollateralOptions = this.codeValueReadPlatformService
|
||||||
.retrieveCodeValuesByCode("LoanCollateral");
|
.retrieveCodeValuesByCode("LoanCollateral");
|
||||||
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId,
|
Collection<ChargeData> chargeOptions = null;
|
||||||
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT });
|
if(loanProduct.getMultiDisburseLoan()){
|
||||||
|
chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId,
|
||||||
|
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT });
|
||||||
|
}else{
|
||||||
|
chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId,
|
||||||
|
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT });
|
||||||
|
}
|
||||||
|
|
||||||
Integer loanCycleCounter = null;
|
Integer loanCycleCounter = null;
|
||||||
if (loanProduct.useBorrowerCycle()) {
|
if (loanProduct.useBorrowerCycle()) {
|
||||||
if (clientId == null) {
|
if (clientId == null) {
|
||||||
@@ -1441,17 +1461,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DisbursementData> retrieveLoanDisbursementDetails(final Long loanId) {
|
public Collection<DisbursementData> retrieveLoanDisbursementDetails
|
||||||
|
(final Long loanId) {
|
||||||
final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper();
|
final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper();
|
||||||
final String sql = "select " + rm.schema() + " where dd.loan_id=? order by dd.expected_disburse_date";
|
final String sql = "select " + rm.schema() + " where dd.loan_id=? group by dd.id order by dd.expected_disburse_date";
|
||||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class LoanDisbursementDetailMapper implements RowMapper<DisbursementData> {
|
private static final class LoanDisbursementDetailMapper implements RowMapper<DisbursementData> {
|
||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
return "dd.id as id,dd.expected_disburse_date as expectedDisbursementdate,dd.disbursedon_date as actualDisbursementdate,dd.principal as principal "
|
return "dd.id as id,dd.expected_disburse_date as expectedDisbursementdate, dd.disbursedon_date as actualDisbursementdate,dd.principal as principal,sum(lc.amount) chargeAmount, lc.amount_waived_derived waivedAmount,group_concat(lc.id) loanChargeId "+
|
||||||
+ "from m_loan_disbursement_detail dd";
|
"from m_loan l inner join m_loan_disbursement_detail dd on dd.loan_id = l.id left join m_loan_tranche_disbursement_charge tdc on tdc.disbursement_detail_id=dd.id " +
|
||||||
|
"left join m_loan_charge lc on lc.id=tdc.loan_charge_id and lc.is_active=1";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1460,8 +1482,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final LocalDate expectedDisbursementdate = JdbcSupport.getLocalDate(rs, "expectedDisbursementdate");
|
final LocalDate expectedDisbursementdate = JdbcSupport.getLocalDate(rs, "expectedDisbursementdate");
|
||||||
final LocalDate actualDisbursementdate = JdbcSupport.getLocalDate(rs, "actualDisbursementdate");
|
final LocalDate actualDisbursementdate = JdbcSupport.getLocalDate(rs, "actualDisbursementdate");
|
||||||
final BigDecimal principal = rs.getBigDecimal("principal");
|
final BigDecimal principal = rs.getBigDecimal("principal");
|
||||||
|
final String loanChargeId = rs.getString("loanChargeId");
|
||||||
final DisbursementData disbursementData = new DisbursementData(id, expectedDisbursementdate, actualDisbursementdate, principal);
|
BigDecimal chargeAmount = rs.getBigDecimal("chargeAmount");
|
||||||
|
final BigDecimal waivedAmount = rs.getBigDecimal("waivedAmount") ;
|
||||||
|
if(chargeAmount != null && waivedAmount != null)
|
||||||
|
chargeAmount = chargeAmount.subtract(waivedAmount) ;
|
||||||
|
final DisbursementData disbursementData = new DisbursementData(id, expectedDisbursementdate, actualDisbursementdate, principal, loanChargeId,
|
||||||
|
chargeAmount);
|
||||||
return disbursementData;
|
return disbursementData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+51
-12
@@ -76,6 +76,7 @@ import org.mifosplatform.portfolio.calendar.exception.CalendarParameterUpdateNot
|
|||||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
|
import org.mifosplatform.portfolio.charge.exception.ChargeCannotBeUpdatedException;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
|
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.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
|
||||||
@@ -120,6 +121,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInsta
|
|||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
|
||||||
@@ -1301,6 +1303,20 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateAddingNewChargeAllowed(Set<LoanDisbursementDetails> loanDisburseDetails) {
|
||||||
|
boolean pendingDisbursementAvailable = false;
|
||||||
|
for (LoanDisbursementDetails disbursementDetail : loanDisburseDetails) {
|
||||||
|
if (disbursementDetail.actualDisbursementDate() == null) {
|
||||||
|
pendingDisbursementAvailable = true ;
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!pendingDisbursementAvailable) {
|
||||||
|
throw new ChargeCannotBeUpdatedException(
|
||||||
|
"error.msg.charge.cannot.be.updated.no.pending.disbursements.in.loan", "This charge cannot be added, No disbursement is pending");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult addLoanCharge(final Long loanId, final JsonCommand command) {
|
public CommandProcessingResult addLoanCharge(final Long loanId, final JsonCommand command) {
|
||||||
@@ -1310,19 +1326,42 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||||
checkClientOrGroupActive(loan);
|
checkClientOrGroupActive(loan);
|
||||||
|
|
||||||
|
Set<LoanDisbursementDetails> loanDisburseDetails = loan.getDisbursementDetails();
|
||||||
final Long chargeDefinitionId = command.longValueOfParameterNamed("chargeId");
|
final Long chargeDefinitionId = command.longValueOfParameterNamed("chargeId");
|
||||||
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeDefinitionId);
|
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeDefinitionId);
|
||||||
|
|
||||||
final LoanCharge loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, command);
|
if(loan.isDisbursed() && chargeDefinition.isDisbursementCharge()) {
|
||||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_ADD_CHARGE,
|
validateAddingNewChargeAllowed(loanDisburseDetails) ; //validates whether any pending disbursements are available to apply this charge
|
||||||
constructEntityMap(BUSINESS_ENTITY.LOAN_CHARGE, loanCharge));
|
}
|
||||||
|
|
||||||
validateAddLoanCharge(loan, chargeDefinition, loanCharge);
|
|
||||||
|
|
||||||
final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
|
final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
|
||||||
final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
|
final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
|
||||||
|
|
||||||
boolean isAppliedOnBackDate = addCharge(loan, chargeDefinition, loanCharge);
|
boolean isAppliedOnBackDate = false;
|
||||||
|
LoanCharge loanCharge = null;
|
||||||
|
if (chargeDefinition.isPercentageOfDisbursementAmount()) {
|
||||||
|
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null;
|
||||||
|
for (LoanDisbursementDetails disbursementDetail : loanDisburseDetails) {
|
||||||
|
if (disbursementDetail.actualDisbursementDate() == null) {
|
||||||
|
loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, disbursementDetail.principal(), null, null, null,
|
||||||
|
disbursementDetail.expectedDisbursementDateAsLocalDate(), null, null);
|
||||||
|
loanTrancheDisbursementCharge = new LoanTrancheDisbursementCharge(loanCharge, disbursementDetail);
|
||||||
|
loanCharge.updateLoanTrancheDisbursementCharge(loanTrancheDisbursementCharge);
|
||||||
|
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_ADD_CHARGE,
|
||||||
|
constructEntityMap(BUSINESS_ENTITY.LOAN_CHARGE, loanCharge));
|
||||||
|
validateAddLoanCharge(loan, chargeDefinition, loanCharge);
|
||||||
|
isAppliedOnBackDate = addCharge(loan, chargeDefinition, loanCharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loan.addTrancheLoanCharge(chargeDefinition);
|
||||||
|
} else {
|
||||||
|
loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, command);
|
||||||
|
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_ADD_CHARGE,
|
||||||
|
constructEntityMap(BUSINESS_ENTITY.LOAN_CHARGE, loanCharge));
|
||||||
|
|
||||||
|
validateAddLoanCharge(loan, chargeDefinition, loanCharge);
|
||||||
|
isAppliedOnBackDate = addCharge(loan, chargeDefinition, loanCharge);
|
||||||
|
}
|
||||||
|
|
||||||
boolean reprocessRequired = true;
|
boolean reprocessRequired = true;
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
if (isAppliedOnBackDate && loan.isFeeCompoundingEnabledForInterestRecalculation()) {
|
if (isAppliedOnBackDate && loan.isFeeCompoundingEnabledForInterestRecalculation()) {
|
||||||
@@ -1331,7 +1370,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
updateOriginalSchedule(loan);
|
updateOriginalSchedule(loan);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reprocessRequired) {
|
if (reprocessRequired) {
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactions();
|
ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactions();
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
@@ -1480,10 +1518,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loanChargeRepository.save(loanCharge);
|
|
||||||
|
|
||||||
loan.addLoanCharge(loanCharge);
|
loan.addLoanCharge(loanCharge);
|
||||||
|
|
||||||
|
this.loanChargeRepository.save(loanCharge);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we want to apply charge transactions only for those loans charges
|
* we want to apply charge transactions only for those loans charges
|
||||||
* that are applied when a loan is active and the loan product uses
|
* that are applied when a loan is active and the loan product uses
|
||||||
@@ -2349,7 +2387,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void applyOverdueChargesForLoan(final Long loanId, Collection<OverdueLoanScheduleData> overdueLoanScheduleDatas) {
|
public void applyOverdueChargesForLoan(final Long loanId, Collection<OverdueLoanScheduleData> overdueLoanScheduleDatas) {
|
||||||
@@ -2652,10 +2689,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
changedTransactionDetail = loan.updateDisbursementDateAndAmountForTranche(loanDisbursementDetails, command,
|
changedTransactionDetail = loan.updateDisbursementDateAndAmountForTranche(loanDisbursementDetails, command,
|
||||||
existingTransactionIds, existingReversedTransactionIds, changes, scheduleGeneratorDTO, currentUser);
|
existingTransactionIds, existingReversedTransactionIds, changes, scheduleGeneratorDTO, currentUser);
|
||||||
} else {
|
} else {
|
||||||
|
// BigDecimal setAmount = loan.getApprovedPrincipal();
|
||||||
Collection<LoanDisbursementDetails> loanDisburseDetails = loan.getDisbursementDetails();
|
Collection<LoanDisbursementDetails> loanDisburseDetails = loan.getDisbursementDetails();
|
||||||
BigDecimal setAmount = BigDecimal.ZERO;
|
BigDecimal setAmount = BigDecimal.ZERO;
|
||||||
for (LoanDisbursementDetails details : loanDisburseDetails) {
|
for (LoanDisbursementDetails details : loanDisburseDetails) {
|
||||||
if (details.actualDisbursementDate() != null) {
|
if (details.expectedDisbursementDate() != null) {
|
||||||
setAmount = setAmount.add(details.principal());
|
setAmount = setAmount.add(details.principal());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2666,6 +2704,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loan.regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
|
loan.regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
|
||||||
} else {
|
} else {
|
||||||
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
|
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
|
||||||
|
loan.processPostDisbursementTransactions() ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -19,6 +19,7 @@ import javax.persistence.CascadeType;
|
|||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Embedded;
|
import javax.persistence.Embedded;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.JoinTable;
|
import javax.persistence.JoinTable;
|
||||||
import javax.persistence.ManyToMany;
|
import javax.persistence.ManyToMany;
|
||||||
@@ -83,7 +84,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "description")
|
@Column(name = "description")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@ManyToMany
|
@ManyToMany(fetch = FetchType.EAGER)
|
||||||
@JoinTable(name = "m_product_loan_charge", joinColumns = @JoinColumn(name = "product_loan_id"), inverseJoinColumns = @JoinColumn(name = "charge_id"))
|
@JoinTable(name = "m_product_loan_charge", joinColumns = @JoinColumn(name = "product_loan_id"), inverseJoinColumns = @JoinColumn(name = "charge_id"))
|
||||||
private List<Charge> charges;
|
private List<Charge> charges;
|
||||||
|
|
||||||
@@ -603,6 +604,10 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
return this.accountingRule;
|
return this.accountingRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Charge> getLoanProductCharges(){
|
||||||
|
return this.charges;
|
||||||
|
}
|
||||||
|
|
||||||
public void update(final LoanProductConfigurableAttributes loanConfigurableAttributes) {
|
public void update(final LoanProductConfigurableAttributes loanConfigurableAttributes) {
|
||||||
this.loanConfigurableAttributes = loanConfigurableAttributes;
|
this.loanConfigurableAttributes = loanConfigurableAttributes;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -153,7 +153,7 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
|||||||
this.savingsAccount = savingsAccount;
|
this.savingsAccount = savingsAccount;
|
||||||
this.charge = chargeDefinition;
|
this.charge = chargeDefinition;
|
||||||
this.penaltyCharge = chargeDefinition.isPenalty();
|
this.penaltyCharge = chargeDefinition.isPenalty();
|
||||||
this.chargeTime = (chargeTime == null) ? chargeDefinition.getChargeTime() : chargeTime.getValue();
|
this.chargeTime = (chargeTime == null) ? chargeDefinition.getChargeTimeType() : chargeTime.getValue();
|
||||||
|
|
||||||
if (isOnSpecifiedDueDate()) {
|
if (isOnSpecifiedDueDate()) {
|
||||||
if (dueDate == null) {
|
if (dueDate == null) {
|
||||||
|
|||||||
+2
-2
@@ -134,8 +134,8 @@ public class SavingsAccountChargeAssembler {
|
|||||||
Set<Charge> productCharges = savingsProduct.charges();
|
Set<Charge> productCharges = savingsProduct.charges();
|
||||||
for (Charge charge : productCharges) {
|
for (Charge charge : productCharges) {
|
||||||
ChargeTimeType chargeTime = null;
|
ChargeTimeType chargeTime = null;
|
||||||
if (charge.getChargeTime() != null) {
|
if (charge.getChargeTimeType() != null) {
|
||||||
chargeTime = ChargeTimeType.fromInt(charge.getChargeTime());
|
chargeTime = ChargeTimeType.fromInt(charge.getChargeTimeType());
|
||||||
}
|
}
|
||||||
if (chargeTime != null && chargeTime.isOnSpecifiedDueDate()) {
|
if (chargeTime != null && chargeTime.isOnSpecifiedDueDate()) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
CREATE TABLE `m_loan_tranche_disbursement_charge` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`loan_charge_id` BIGINT(20) NOT NULL,
|
||||||
|
`disbursement_detail_id` BIGINT(20) NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
)
|
||||||
|
COLLATE='utf8_general_ci'
|
||||||
|
ENGINE=InnoDB
|
||||||
|
AUTO_INCREMENT=1
|
||||||
|
;
|
||||||
|
|
||||||
|
ALTER TABLE `m_loan_tranche_disbursement_charge`
|
||||||
|
ADD CONSTRAINT `FK_m_loan_tranche_disbursement_charge_m_loan_charge` FOREIGN KEY (`loan_charge_id`) REFERENCES `m_loan_charge` (`id`),
|
||||||
|
ADD CONSTRAINT `FK_m_loan_tranche_disbursement_charge_m_loan_disbursement_detail` FOREIGN KEY (`disbursement_detail_id`) REFERENCES `m_loan_disbursement_detail` (`id`);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE `m_loan_tranche_charges` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`loan_id` BIGINT(20) NOT NULL,
|
||||||
|
`charge_id` BIGINT(20) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
ALTER TABLE `m_loan_tranche_charges`
|
||||||
|
ADD CONSTRAINT `FK_m_loan_tranche_charges_m_loan` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`),
|
||||||
|
ADD CONSTRAINT `FK_m_loan_tranche_charges_m_charge` FOREIGN KEY (`charge_id`) REFERENCES `m_charge` (`id`);
|
||||||
Reference in New Issue
Block a user