diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 202a63333..deafac853 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -11283,7 +11283,9 @@ Request Body: "chargeCalculationType": "2", "chargePaymentMode": "1", "active": "true", - "penalty": "true" + "penalty": "true", + "minCap": 50.00, + "maxCap": 100.00 } @@ -11389,7 +11391,49 @@ GET https://DomainName/api/v1/charges "code":"chargepaymentmode.accounttransfer", "value":"Account transfer" } - } + }, + { + "id": 54, + "chargeId": 12, + "name": "Loan service fee 2", + "chargeTimeType": { + "id": 1, + "code": "chargeTimeType.disbursement", + "value": "Disbursement" + }, + "chargeCalculationType": { + "id": 2, + "code": "chargeCalculationType.percent.of.amount", + "value": "% Amount" + }, + "percentage": 2.000000, + "amountPercentageAppliedTo": 14000.000000, + "currency": { + "code": "KES", + "name": "Kenyan Shilling", + "decimalPlaces": 2, + "displaySymbol": "KSh", + "nameCode": "currency.KES", + "displayLabel": "Kenyan Shilling (KSh)" + }, + "amount": 500.000000, + "amountPaid": 0, + "amountWaived": 0, + "amountWrittenOff": 0, + "amountOutstanding": 500.000000, + "amountOrPercentage": 2.000000, + "penalty": false, + "chargePaymentMode": { + "id": 1, + "code": "chargepaymentmode.accounttransfer", + "value": "Account transfer" + }, + "paid": false, + "waived": false, + "chargePayable": true, + "minCap": 500.000000, + "maxCap": 1000.000000 + }, ] diff --git a/mifosng-db/migrations/core_db/V124__added_min_max_cap_for_charges.sql b/mifosng-db/migrations/core_db/V124__added_min_max_cap_for_charges.sql new file mode 100755 index 000000000..eb762a805 --- /dev/null +++ b/mifosng-db/migrations/core_db/V124__added_min_max_cap_for_charges.sql @@ -0,0 +1,8 @@ +ALTER TABLE `m_charge` +ADD COLUMN `min_cap` DECIMAL(19,6) NULL AFTER `is_deleted`, +ADD COLUMN `max_cap` DECIMAL(19,6) NULL AFTER `min_cap`; + +ALTER TABLE `m_loan_charge` +ADD COLUMN `min_cap` DECIMAL(19,6) NULL AFTER `waived`, +ADD COLUMN `max_cap` DECIMAL(19,6) NULL AFTER `min_cap`; + diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java old mode 100644 new mode 100755 index 74eeb4fc1..7a27e36d1 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/data/ChargeData.java @@ -34,6 +34,8 @@ public class ChargeData implements Comparable, Serializable { private final EnumOptionData chargePaymentMode; private final MonthDay feeOnMonthDay; private final Integer feeInterval; + private final BigDecimal minCap; + private final BigDecimal maxCap; private final Collection currencyOptions; private final List chargeCalculationTypeOptions;// @@ -54,20 +56,21 @@ public class ChargeData implements Comparable, Serializable { return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions, - loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, null, null); + loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, null, null,null,null); } public static ChargeData withTemplate(final ChargeData charge, final ChargeData template) { return new ChargeData(charge.id, charge.name, charge.amount, charge.currency, charge.chargeTimeType, charge.chargeAppliesTo, - charge.chargeCalculationType, charge.chargePaymentMode, charge.penalty, charge.active, template.currencyOptions, + charge.chargeCalculationType, charge.chargePaymentMode, charge.penalty, charge.active,template.currencyOptions, template.chargeCalculationTypeOptions, template.chargeAppliesToOptions, template.chargeTimeTypeOptions, template.chargePaymetModeOptions, template.loanChargeCalculationTypeOptions, template.loanChargeTimeTypeOptions, - template.savingsChargeCalculationTypeOptions, template.savingsChargeTimeTypeOptions, charge.feeOnMonthDay, charge.feeInterval); + template.savingsChargeCalculationTypeOptions, template.savingsChargeTimeTypeOptions, charge.feeOnMonthDay, charge.feeInterval,charge.minCap,charge.maxCap); } public static ChargeData instance(final Long id, final String name, final BigDecimal amount, final CurrencyData currency, final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType, - final EnumOptionData chargePaymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, final boolean penalty, final boolean active) { + final EnumOptionData chargePaymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, final boolean penalty, final boolean active, + final BigDecimal minCap, final BigDecimal maxCap) { final Collection currencyOptions = null; final List chargeCalculationTypeOptions = null; @@ -82,7 +85,7 @@ public class ChargeData implements Comparable, Serializable { return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode, penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, - savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval); + savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval,minCap,maxCap); } public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) { @@ -96,6 +99,8 @@ public class ChargeData implements Comparable, Serializable { final Integer feeInterval = null; final Boolean penalty = isPenalty; final Boolean active = false; + final BigDecimal minCap = null; + final BigDecimal maxCap = null; final Collection currencyOptions = null; final List chargeCalculationTypeOptions = null; final List chargeAppliesToOptions = null; @@ -109,7 +114,7 @@ public class ChargeData implements Comparable, Serializable { return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode, penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, - savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval); + savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval,minCap,maxCap); } private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency, @@ -119,7 +124,8 @@ public class ChargeData implements Comparable, Serializable { final List chargeAppliesToOptions, final List chargeTimeTypeOptions, final List chargePaymentModeOptions, final List loansChargeCalculationTypeOptions, final List loansChargeTimeTypeOptions, final List savingsChargeCalculationTypeOptions, - final List savingsChargeTimeTypeOptions, final MonthDay feeOnMonthDay, final Integer feeInterval) { + final List savingsChargeTimeTypeOptions, final MonthDay feeOnMonthDay, final Integer feeInterval, + final BigDecimal minCap,final BigDecimal maxCap) { this.id = id; this.name = name; this.amount = amount; @@ -132,6 +138,8 @@ public class ChargeData implements Comparable, Serializable { this.feeOnMonthDay = feeOnMonthDay; this.penalty = penalty; this.active = active; + this.minCap = minCap; + this.maxCap = maxCap; this.currencyOptions = currencyOptions; this.chargeCalculationTypeOptions = chargeCalculationTypeOptions; this.chargeAppliesToOptions = chargeAppliesToOptions; @@ -169,7 +177,7 @@ public class ChargeData implements Comparable, Serializable { } return LoanChargeData.newLoanChargeDetails(this.id, this.name, this.currency, this.amount, percentage, this.chargeTimeType, - this.chargeCalculationType, this.penalty, this.chargePaymentMode); + this.chargeCalculationType, this.penalty, this.chargePaymentMode,this.minCap,this.maxCap); } public SavingsAccountChargeData toSavingsAccountChargeData() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java old mode 100644 new mode 100755 index ffe0f8964..dbf7d6944 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java @@ -75,6 +75,13 @@ public class Charge extends AbstractPersistable { @Column(name = "is_deleted", nullable = false) private boolean deleted = false; + @Column(name = "min_cap", scale = 6, precision = 19, nullable = true) + private BigDecimal minCap; + + @Column(name = "max_cap", scale = 6, precision = 19, nullable = true) + private BigDecimal maxCap; + + public static Charge fromJson(final JsonCommand command) { final String name = command.stringValueOfParameterNamed("name"); @@ -93,9 +100,11 @@ public class Charge extends AbstractPersistable { final boolean active = command.booleanPrimitiveValueOfParameterNamed("active"); final MonthDay feeOnMonthDay = command.extractMonthDayNamed("feeOnMonthDay"); final Integer feeInterval = command.integerValueOfParameterNamed("feeInterval"); + final BigDecimal minCap = command.bigDecimalValueOfParameterNamed("minCap"); + final BigDecimal maxCap = command.bigDecimalValueOfParameterNamed("maxCap"); return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active, paymentMode, - feeOnMonthDay, feeInterval); + feeOnMonthDay, feeInterval,minCap,maxCap); } protected Charge() { @@ -104,7 +113,8 @@ public class Charge extends AbstractPersistable { private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo, final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, - final boolean active, final ChargePaymentMode paymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval) { + final boolean active, final ChargePaymentMode paymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, + final BigDecimal minCap, final BigDecimal maxCap) { this.name = name; this.amount = amount; this.currencyCode = currencyCode; @@ -114,6 +124,8 @@ public class Charge extends AbstractPersistable { this.penalty = penalty; this.active = active; this.chargePaymentMode = (paymentMode == null) ? null : paymentMode.getValue(); + this.minCap = minCap; + this.maxCap = maxCap; final List dataValidationErrors = new ArrayList(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charges"); @@ -224,6 +236,19 @@ public class Charge extends AbstractPersistable { return ChargeCalculationType.fromInt(this.chargeCalculation).isAllowedSavingsChargeCalculationType(); } + public boolean isPercentageOfAmount(){ + return ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfAmount(); + } + + public BigDecimal getMinCap() { + return this.minCap; + } + + + public BigDecimal getMaxCap() { + return this.maxCap; + } + public Map update(final JsonCommand command) { final Map actualChanges = new LinkedHashMap(7); @@ -367,6 +392,25 @@ public class Charge extends AbstractPersistable { actualChanges.put(activeParamName, newValue); this.active = newValue; } + //allow min and max cap to be only added to PERCENT_OF_AMOUNT for now + if(isPercentageOfAmount()){ + final String minCapParamName = "minCap"; + if (command.isChangeInBigDecimalParameterNamed(minCapParamName, this.minCap)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minCapParamName); + actualChanges.put(minCapParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.minCap = newValue; + } + final String maxCapParamName = "maxCap"; + if (command.isChangeInBigDecimalParameterNamed(maxCapParamName, this.maxCap)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxCapParamName); + actualChanges.put(maxCapParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.maxCap = newValue; + } + } + + if (this.penalty && ChargeTimeType.fromInt(this.chargeTime).isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException( this.name); } @@ -395,7 +439,7 @@ public class Charge extends AbstractPersistable { final EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode); final CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null); return ChargeData.instance(getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, - chargePaymentmode, this.getFeeOnMonthDay(), this.feeInterval, this.penalty, this.active); + chargePaymentmode, this.getFeeOnMonthDay(), this.feeInterval, this.penalty, this.active,this.minCap,this.maxCap); } public Integer getChargePaymentMode() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java old mode 100644 new mode 100755 index 122053f06..050d4f76f --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java @@ -38,7 +38,7 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer { */ private final Set supportedParameters = new HashSet(Arrays.asList("name", "amount", "locale", "currencyCode", "currencyOptions", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "penalty", - "active", "chargePaymentMode", "feeOnMonthDay", "feeInterval", "monthDayFormat")); + "active", "chargePaymentMode", "feeOnMonthDay", "feeInterval", "monthDayFormat","minCap","maxCap")); private final FromJsonHelper fromApiJsonHelper; @@ -84,7 +84,7 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer { final Integer chargePaymentMode = this.fromApiJsonHelper.extractIntegerNamed("chargePaymentMode", element, Locale.getDefault()); baseDataValidator.reset().parameter("chargePaymentMode").value(chargePaymentMode).notNull().inMinMaxRange(0, 1); } - + if (this.fromApiJsonHelper.parameterExists("penalty", element)) { final Boolean penalty = this.fromApiJsonHelper.extractBooleanNamed("penalty", element); baseDataValidator.reset().parameter("penalty").value(penalty).notNull(); @@ -109,6 +109,15 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer { baseDataValidator.reset().parameter("feeOnMonthDay").value(monthDay).notNull(); } + if(this.fromApiJsonHelper.parameterExists("minCap",element)){ + final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minCap", element.getAsJsonObject()); + baseDataValidator.reset().parameter("minCap").value(minCap).notNull().positiveAmount(); + } + if(this.fromApiJsonHelper.parameterExists("maxCap",element)){ + final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("maxCap", element.getAsJsonObject()); + baseDataValidator.reset().parameter("maxCap").value(maxCap).notNull().positiveAmount(); + } + throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -137,6 +146,16 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer { baseDataValidator.reset().parameter("amount").value(amount).notNull().positiveAmount(); } + if(this.fromApiJsonHelper.parameterExists("minCap",element)){ + final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minCap", element.getAsJsonObject()); + baseDataValidator.reset().parameter("minCap").value(minCap).notNull().positiveAmount(); + } + + if(this.fromApiJsonHelper.parameterExists("maxCap",element)){ + final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("maxCap", element.getAsJsonObject()); + baseDataValidator.reset().parameter("maxCap").value(maxCap).notNull().positiveAmount(); + } + if (this.fromApiJsonHelper.parameterExists("chargeAppliesTo", element)) { final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerNamed("chargeAppliesTo", element, Locale.getDefault()); baseDataValidator.reset().parameter("chargeAppliesTo").value(chargeAppliesTo).notNull() @@ -179,6 +198,14 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer { final Boolean active = this.fromApiJsonHelper.extractBooleanNamed("active", element); baseDataValidator.reset().parameter("active").value(active).notNull(); } + if(this.fromApiJsonHelper.parameterExists("minCap",element)){ + final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minCap", element.getAsJsonObject()); + baseDataValidator.reset().parameter("minCap").value(minCap).notNull().positiveAmount(); + } + if(this.fromApiJsonHelper.parameterExists("maxCap",element)){ + final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("maxCap", element.getAsJsonObject()); + baseDataValidator.reset().parameter("maxCap").value(maxCap).notNull().positiveAmount(); + } throwExceptionIfValidationWarningsExist(dataValidationErrors); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java old mode 100644 new mode 100755 index f5b2ee581..313e441b3 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java @@ -145,7 +145,8 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService + "c.is_active as active, oc.name as currencyName, oc.decimal_places as currencyDecimalPlaces, " + "oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, " + "oc.internationalized_name_code as currencyNameCode, c.fee_on_day as feeOnDay, c.fee_on_month as feeOnMonth, " - + "c.fee_interval as feeInterval from m_charge c " + + "c.fee_interval as feeInterval,c.min_cap as minCap,c.max_cap as maxCap " + + "from m_charge c " + "join m_organisation_currency oc on c.currency_code = oc.code"; } @@ -195,9 +196,11 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService if (feeOnDay != null) { feeOnMonthDay = new MonthDay(feeOnMonth, feeOnDay); } + final BigDecimal minCap = rs.getBigDecimal("minCap"); + final BigDecimal maxCap = rs.getBigDecimal("maxCap"); return ChargeData.instance(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType, - chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active); + chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active,minCap,maxCap); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanChargeData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanChargeData.java old mode 100644 new mode 100755 index 6c5ae04dc..1a1e65fc9 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanChargeData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanChargeData.java @@ -72,8 +72,12 @@ public class LoanChargeData { private final Long loanId; + private final BigDecimal minCap; + + private final BigDecimal maxCap; + public static LoanChargeData template(final Collection chargeOptions) { - return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null); + return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null,null,null); } /** @@ -82,16 +86,17 @@ public class LoanChargeData { */ public static LoanChargeData newLoanChargeDetails(final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount, final BigDecimal percentage, final EnumOptionData chargeTimeType, - final EnumOptionData chargeCalculationType, final boolean penalty, final EnumOptionData chargePaymentMode) { + final EnumOptionData chargeCalculationType, final boolean penalty, final EnumOptionData chargePaymentMode,final BigDecimal minCap,final BigDecimal maxCap) { return new LoanChargeData(null, chargeId, name, currency, amount, percentage, chargeTimeType, chargeCalculationType, null, penalty, - chargePaymentMode, false, false, null); + chargePaymentMode, false, false, null,minCap,maxCap); } public LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount, final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff, final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueDate, final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo, - final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid, final boolean waived, final Long loanId) { + final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid, final boolean waived, final Long loanId, + final BigDecimal minCap, final BigDecimal maxCap) { this.id = id; this.chargeId = chargeId; this.name = name; @@ -110,6 +115,8 @@ public class LoanChargeData { this.chargePaymentMode = chargePaymentMode; this.paid = paid; this.waived = waived; + this.minCap = minCap; + this.maxCap = maxCap; if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) { this.amountOrPercentage = this.percentage; @@ -123,9 +130,9 @@ public class LoanChargeData { } private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount, - final BigDecimal pecentage, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType, + final BigDecimal percentage, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType, final Collection chargeOptions, final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid, - final boolean waived, final Long loanId) { + final boolean waived, final Long loanId,final BigDecimal minCap, final BigDecimal maxCap) { this.id = id; this.chargeId = chargeId; this.name = name; @@ -138,13 +145,15 @@ public class LoanChargeData { this.chargeTimeType = chargeTimeType; this.dueDate = null; this.chargeCalculationType = chargeCalculationType; - this.percentage = pecentage; + this.percentage = percentage; this.amountPercentageAppliedTo = null; this.penalty = penalty; this.chargePaymentMode = chargePaymentMode; this.paid = paid; this.waived = waived; + + if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) { this.amountOrPercentage = this.percentage; } else { @@ -154,6 +163,8 @@ public class LoanChargeData { this.chargeOptions = chargeOptions; this.chargePayable = isChargePayable(); this.loanId = loanId; + this.minCap = minCap; + this.maxCap = maxCap; } public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOutstanding, final Long loanId) { @@ -179,6 +190,8 @@ public class LoanChargeData { this.chargeOptions = null; this.chargePayable = false; this.loanId = loanId; + this.minCap = null; + this.maxCap = null; } public boolean isChargePayable() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java old mode 100644 new mode 100755 index 9319ac09e..0d97ec2a6 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCharge.java @@ -89,6 +89,12 @@ public class LoanCharge extends AbstractPersistable { @Column(name = "waived", nullable = false) private boolean waived = false; + @Column(name = "min_cap", scale = 6, precision = 19, nullable = true) + private BigDecimal minCap; + + @Column(name = "max_cap", scale = 6, precision = 19, nullable = true) + private BigDecimal maxCap; + public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) { final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount"); @@ -121,6 +127,8 @@ public class LoanCharge extends AbstractPersistable { this.loan = loan; this.charge = chargeDefinition; this.penaltyCharge = chargeDefinition.isPenalty(); + this.minCap = chargeDefinition.getMinCap(); + this.maxCap = chargeDefinition.getMaxCap(); this.chargeTime = chargeDefinition.getChargeTime(); if (chargeTime != null) { @@ -155,7 +163,7 @@ public class LoanCharge extends AbstractPersistable { this.chargePaymentMode = chargePaymentMode.getValue(); } - populateDerivedFields(loanPrincipal, chargeAmount); + populateDerivedFields(loanPrincipal,chargeAmount); this.paid = determineIfFullyPaid(); } @@ -183,7 +191,7 @@ public class LoanCharge extends AbstractPersistable { case PERCENT_OF_AMOUNT: this.percentage = chargeAmount; this.amountPercentageAppliedTo = loanPrincipal; - this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage); + this.amount = minimumAndMaximumCap(percentageOf(this.amountPercentageAppliedTo, this.percentage)); this.amountPaid = null; this.amountOutstanding = calculateOutstanding(); this.amountWaived = null; @@ -262,7 +270,7 @@ public class LoanCharge extends AbstractPersistable { case PERCENT_OF_AMOUNT: this.percentage = amount; this.amountPercentageAppliedTo = loanPrincipal; - this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage); + this.amount = minimumAndMaximumCap(percentageOf(this.amountPercentageAppliedTo, this.percentage)); this.amountOutstanding = calculateOutstanding(); break; case PERCENT_OF_AMOUNT_AND_INTEREST: @@ -313,7 +321,7 @@ public class LoanCharge extends AbstractPersistable { case PERCENT_OF_AMOUNT: this.percentage = newValue; this.amountPercentageAppliedTo = loanPrincipal; - this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage); + this.amount = minimumAndMaximumCap(percentageOf(this.amountPercentageAppliedTo, this.percentage)); this.amountOutstanding = calculateOutstanding(); break; case PERCENT_OF_AMOUNT_AND_INTEREST: @@ -393,10 +401,34 @@ public class LoanCharge extends AbstractPersistable { final BigDecimal multiplicand = percentage.divide(BigDecimal.valueOf(100l), mc); percentageOf = value.multiply(multiplicand, mc); } - return percentageOf; } + /** + * @param percentageOf + * @returns a minimum cap or maximum cap set on charges if the criteria fits + * else it returns the percentageOf if the amount is within min and max cap + */ + private BigDecimal minimumAndMaximumCap(BigDecimal percentageOf){ + BigDecimal minMaxCap = BigDecimal.ZERO; + if(this.minCap !=null){ + int minimumCap = percentageOf.compareTo(minCap); + if(minimumCap == -1){ + minMaxCap = this.minCap; + return minMaxCap; + } + } + if(this.maxCap !=null){ + int maximumCap = percentageOf.compareTo(maxCap); + if(maximumCap == 1) { + minMaxCap = this.maxCap; + return minMaxCap; + } + } + minMaxCap = percentageOf; + return minMaxCap; + } + public BigDecimal amount() { return this.amount; } @@ -443,6 +475,14 @@ public class LoanCharge extends AbstractPersistable { return this.waived; } + public BigDecimal getMinCap() { + return this.minCap; + } + + public BigDecimal getMaxCap() { + return this.maxCap; + } + public boolean isPaidOrPartiallyPaid(final MonetaryCurrency currency) { final Money amountWaivedOrWrittenOff = getAmountWaived(currency).plus(getAmountWrittenOff(currency)); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java old mode 100644 new mode 100755 index d4bcac095..26f18b154 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java @@ -58,6 +58,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform + "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, " + "c.currency_code as currencyCode, oc.name as currencyName, " + "oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, " + "oc.internationalized_name_code as currencyNameCode from m_charge c " @@ -102,10 +103,12 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform final EnumOptionData paymentMode = ChargeEnumerations.chargePaymentMode(chargePaymentMode); final boolean paid = rs.getBoolean("paid"); final boolean waived = rs.getBoolean("waied"); + final BigDecimal minCap = rs.getBigDecimal("minCap"); + final BigDecimal maxCap = rs.getBigDecimal("maxCap"); return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding, chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty, paymentMode, - paid, waived, null); + paid, waived, null,minCap,maxCap); } }