fix for Mifosx-437

This commit is contained in:
andrew-dzak
2013-10-17 16:44:04 +02:00
parent f898c5fcff
commit e1c2d36d10
9 changed files with 220 additions and 30 deletions
+46 -2
View File
@@ -11283,7 +11283,9 @@ Request Body:
"chargeCalculationType": "2", "chargeCalculationType": "2",
"chargePaymentMode": "1", "chargePaymentMode": "1",
"active": "true", "active": "true",
"penalty": "true" "penalty": "true",
"minCap": 50.00,
"maxCap": 100.00
} }
</code> </code>
<code class="method-response"> <code class="method-response">
@@ -11389,7 +11391,49 @@ GET https://DomainName/api/v1/charges
"code":"chargepaymentmode.accounttransfer", "code":"chargepaymentmode.accounttransfer",
"value":"Account transfer" "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
},
] ]
</code> </code>
</div> </div>
@@ -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`;
@@ -34,6 +34,8 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
private final EnumOptionData chargePaymentMode; private final EnumOptionData chargePaymentMode;
private final MonthDay feeOnMonthDay; private final MonthDay feeOnMonthDay;
private final Integer feeInterval; private final Integer feeInterval;
private final BigDecimal minCap;
private final BigDecimal maxCap;
private final Collection<CurrencyData> currencyOptions; private final Collection<CurrencyData> currencyOptions;
private final List<EnumOptionData> chargeCalculationTypeOptions;// private final List<EnumOptionData> chargeCalculationTypeOptions;//
@@ -54,20 +56,21 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions, return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions,
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions, 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) { 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, 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.chargeCalculationTypeOptions, template.chargeAppliesToOptions, template.chargeTimeTypeOptions,
template.chargePaymetModeOptions, template.loanChargeCalculationTypeOptions, template.loanChargeTimeTypeOptions, 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, 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 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<CurrencyData> currencyOptions = null; final Collection<CurrencyData> currencyOptions = null;
final List<EnumOptionData> chargeCalculationTypeOptions = null; final List<EnumOptionData> chargeCalculationTypeOptions = null;
@@ -82,7 +85,7 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
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,
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval); savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval,minCap,maxCap);
} }
public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) { public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) {
@@ -96,6 +99,8 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
final Integer feeInterval = null; final Integer feeInterval = null;
final Boolean penalty = isPenalty; final Boolean penalty = isPenalty;
final Boolean active = false; final Boolean active = false;
final BigDecimal minCap = null;
final BigDecimal maxCap = null;
final Collection<CurrencyData> currencyOptions = null; final Collection<CurrencyData> currencyOptions = null;
final List<EnumOptionData> chargeCalculationTypeOptions = null; final List<EnumOptionData> chargeCalculationTypeOptions = null;
final List<EnumOptionData> chargeAppliesToOptions = null; final List<EnumOptionData> chargeAppliesToOptions = null;
@@ -109,7 +114,7 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
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,
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval); savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeOnMonthDay, feeInterval,minCap,maxCap);
} }
private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency, private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
@@ -119,7 +124,8 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
final List<EnumOptionData> chargeAppliesToOptions, final List<EnumOptionData> chargeTimeTypeOptions, final List<EnumOptionData> chargeAppliesToOptions, final List<EnumOptionData> chargeTimeTypeOptions,
final List<EnumOptionData> chargePaymentModeOptions, final List<EnumOptionData> loansChargeCalculationTypeOptions, final List<EnumOptionData> chargePaymentModeOptions, final List<EnumOptionData> loansChargeCalculationTypeOptions,
final List<EnumOptionData> loansChargeTimeTypeOptions, final List<EnumOptionData> savingsChargeCalculationTypeOptions, final List<EnumOptionData> loansChargeTimeTypeOptions, final List<EnumOptionData> savingsChargeCalculationTypeOptions,
final List<EnumOptionData> savingsChargeTimeTypeOptions, final MonthDay feeOnMonthDay, final Integer feeInterval) { final List<EnumOptionData> savingsChargeTimeTypeOptions, final MonthDay feeOnMonthDay, final Integer feeInterval,
final BigDecimal minCap,final BigDecimal maxCap) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.amount = amount; this.amount = amount;
@@ -132,6 +138,8 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
this.feeOnMonthDay = feeOnMonthDay; this.feeOnMonthDay = feeOnMonthDay;
this.penalty = penalty; this.penalty = penalty;
this.active = active; this.active = active;
this.minCap = minCap;
this.maxCap = maxCap;
this.currencyOptions = currencyOptions; this.currencyOptions = currencyOptions;
this.chargeCalculationTypeOptions = chargeCalculationTypeOptions; this.chargeCalculationTypeOptions = chargeCalculationTypeOptions;
this.chargeAppliesToOptions = chargeAppliesToOptions; this.chargeAppliesToOptions = chargeAppliesToOptions;
@@ -169,7 +177,7 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
} }
return LoanChargeData.newLoanChargeDetails(this.id, this.name, this.currency, this.amount, percentage, this.chargeTimeType, 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() { public SavingsAccountChargeData toSavingsAccountChargeData() {
@@ -75,6 +75,13 @@ public class Charge extends AbstractPersistable<Long> {
@Column(name = "is_deleted", nullable = false) @Column(name = "is_deleted", nullable = false)
private boolean deleted = 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) { public static Charge fromJson(final JsonCommand command) {
final String name = command.stringValueOfParameterNamed("name"); final String name = command.stringValueOfParameterNamed("name");
@@ -93,9 +100,11 @@ public class Charge extends AbstractPersistable<Long> {
final boolean active = command.booleanPrimitiveValueOfParameterNamed("active"); final boolean active = command.booleanPrimitiveValueOfParameterNamed("active");
final MonthDay feeOnMonthDay = command.extractMonthDayNamed("feeOnMonthDay"); final MonthDay feeOnMonthDay = command.extractMonthDayNamed("feeOnMonthDay");
final Integer feeInterval = command.integerValueOfParameterNamed("feeInterval"); 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, return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active, paymentMode,
feeOnMonthDay, feeInterval); feeOnMonthDay, feeInterval,minCap,maxCap);
} }
protected Charge() { protected Charge() {
@@ -104,7 +113,8 @@ public class Charge extends AbstractPersistable<Long> {
private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo, private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo,
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, 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.name = name;
this.amount = amount; this.amount = amount;
this.currencyCode = currencyCode; this.currencyCode = currencyCode;
@@ -114,6 +124,8 @@ public class Charge extends AbstractPersistable<Long> {
this.penalty = penalty; this.penalty = penalty;
this.active = active; this.active = active;
this.chargePaymentMode = (paymentMode == null) ? null : paymentMode.getValue(); this.chargePaymentMode = (paymentMode == null) ? null : paymentMode.getValue();
this.minCap = minCap;
this.maxCap = maxCap;
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charges"); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charges");
@@ -224,6 +236,19 @@ public class Charge extends AbstractPersistable<Long> {
return ChargeCalculationType.fromInt(this.chargeCalculation).isAllowedSavingsChargeCalculationType(); 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<String, Object> update(final JsonCommand command) { public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7); final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
@@ -367,6 +392,25 @@ public class Charge extends AbstractPersistable<Long> {
actualChanges.put(activeParamName, newValue); actualChanges.put(activeParamName, newValue);
this.active = 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( if (this.penalty && ChargeTimeType.fromInt(this.chargeTime).isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(
this.name); } this.name); }
@@ -395,7 +439,7 @@ public class Charge extends AbstractPersistable<Long> {
final EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode); final EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode);
final CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null); final CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null);
return ChargeData.instance(getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, 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() { public Integer getChargePaymentMode() {
@@ -38,7 +38,7 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
*/ */
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name", "amount", "locale", "currencyCode", private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name", "amount", "locale", "currencyCode",
"currencyOptions", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "penalty", "currencyOptions", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "penalty",
"active", "chargePaymentMode", "feeOnMonthDay", "feeInterval", "monthDayFormat")); "active", "chargePaymentMode", "feeOnMonthDay", "feeInterval", "monthDayFormat","minCap","maxCap"));
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
@@ -109,6 +109,15 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
baseDataValidator.reset().parameter("feeOnMonthDay").value(monthDay).notNull(); 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); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -137,6 +146,16 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
baseDataValidator.reset().parameter("amount").value(amount).notNull().positiveAmount(); 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)) { if (this.fromApiJsonHelper.parameterExists("chargeAppliesTo", element)) {
final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerNamed("chargeAppliesTo", element, Locale.getDefault()); final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerNamed("chargeAppliesTo", element, Locale.getDefault());
baseDataValidator.reset().parameter("chargeAppliesTo").value(chargeAppliesTo).notNull() baseDataValidator.reset().parameter("chargeAppliesTo").value(chargeAppliesTo).notNull()
@@ -179,6 +198,14 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
final Boolean active = this.fromApiJsonHelper.extractBooleanNamed("active", element); final Boolean active = this.fromApiJsonHelper.extractBooleanNamed("active", element);
baseDataValidator.reset().parameter("active").value(active).notNull(); 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); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -145,7 +145,8 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
+ "c.is_active as active, oc.name as currencyName, oc.decimal_places as currencyDecimalPlaces, " + "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.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, " + "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"; + "join m_organisation_currency oc on c.currency_code = oc.code";
} }
@@ -195,9 +196,11 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
if (feeOnDay != null) { if (feeOnDay != null) {
feeOnMonthDay = new MonthDay(feeOnMonth, feeOnDay); 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, return ChargeData.instance(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType,
chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active); chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active,minCap,maxCap);
} }
} }
@@ -72,8 +72,12 @@ public class LoanChargeData {
private final Long loanId; private final Long loanId;
private final BigDecimal minCap;
private final BigDecimal maxCap;
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); 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, public static LoanChargeData newLoanChargeDetails(final Long chargeId, final String name, final CurrencyData currency,
final BigDecimal amount, final BigDecimal percentage, final EnumOptionData chargeTimeType, 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, 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, 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 amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueDate, final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueDate,
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo, 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.id = id;
this.chargeId = chargeId; this.chargeId = chargeId;
this.name = name; this.name = name;
@@ -110,6 +115,8 @@ public class LoanChargeData {
this.chargePaymentMode = chargePaymentMode; this.chargePaymentMode = chargePaymentMode;
this.paid = paid; this.paid = paid;
this.waived = waived; this.waived = waived;
this.minCap = minCap;
this.maxCap = maxCap;
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) { if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
this.amountOrPercentage = this.percentage; 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, 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<ChargeData> chargeOptions, final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid, final Collection<ChargeData> 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.id = id;
this.chargeId = chargeId; this.chargeId = chargeId;
this.name = name; this.name = name;
@@ -138,13 +145,15 @@ public class LoanChargeData {
this.chargeTimeType = chargeTimeType; this.chargeTimeType = chargeTimeType;
this.dueDate = null; this.dueDate = null;
this.chargeCalculationType = chargeCalculationType; this.chargeCalculationType = chargeCalculationType;
this.percentage = pecentage; this.percentage = percentage;
this.amountPercentageAppliedTo = null; this.amountPercentageAppliedTo = null;
this.penalty = penalty; this.penalty = penalty;
this.chargePaymentMode = chargePaymentMode; this.chargePaymentMode = chargePaymentMode;
this.paid = paid; this.paid = paid;
this.waived = waived; this.waived = waived;
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) { if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
this.amountOrPercentage = this.percentage; this.amountOrPercentage = this.percentage;
} else { } else {
@@ -154,6 +163,8 @@ public class LoanChargeData {
this.chargeOptions = chargeOptions; this.chargeOptions = chargeOptions;
this.chargePayable = isChargePayable(); this.chargePayable = isChargePayable();
this.loanId = loanId; this.loanId = loanId;
this.minCap = minCap;
this.maxCap = maxCap;
} }
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOutstanding, final Long loanId) { 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.chargeOptions = null;
this.chargePayable = false; this.chargePayable = false;
this.loanId = loanId; this.loanId = loanId;
this.minCap = null;
this.maxCap = null;
} }
public boolean isChargePayable() { public boolean isChargePayable() {
@@ -89,6 +89,12 @@ public class LoanCharge extends AbstractPersistable<Long> {
@Column(name = "waived", nullable = false) @Column(name = "waived", nullable = false)
private boolean waived = 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) { public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount"); final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");
@@ -121,6 +127,8 @@ public class LoanCharge extends AbstractPersistable<Long> {
this.loan = loan; this.loan = loan;
this.charge = chargeDefinition; this.charge = chargeDefinition;
this.penaltyCharge = chargeDefinition.isPenalty(); this.penaltyCharge = chargeDefinition.isPenalty();
this.minCap = chargeDefinition.getMinCap();
this.maxCap = chargeDefinition.getMaxCap();
this.chargeTime = chargeDefinition.getChargeTime(); this.chargeTime = chargeDefinition.getChargeTime();
if (chargeTime != null) { if (chargeTime != null) {
@@ -155,7 +163,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
this.chargePaymentMode = chargePaymentMode.getValue(); this.chargePaymentMode = chargePaymentMode.getValue();
} }
populateDerivedFields(loanPrincipal, chargeAmount); populateDerivedFields(loanPrincipal,chargeAmount);
this.paid = determineIfFullyPaid(); this.paid = determineIfFullyPaid();
} }
@@ -183,7 +191,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
case PERCENT_OF_AMOUNT: case PERCENT_OF_AMOUNT:
this.percentage = chargeAmount; this.percentage = chargeAmount;
this.amountPercentageAppliedTo = loanPrincipal; this.amountPercentageAppliedTo = loanPrincipal;
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage); this.amount = minimumAndMaximumCap(percentageOf(this.amountPercentageAppliedTo, this.percentage));
this.amountPaid = null; this.amountPaid = null;
this.amountOutstanding = calculateOutstanding(); this.amountOutstanding = calculateOutstanding();
this.amountWaived = null; this.amountWaived = null;
@@ -262,7 +270,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
case PERCENT_OF_AMOUNT: case PERCENT_OF_AMOUNT:
this.percentage = amount; this.percentage = amount;
this.amountPercentageAppliedTo = loanPrincipal; this.amountPercentageAppliedTo = loanPrincipal;
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage); this.amount = minimumAndMaximumCap(percentageOf(this.amountPercentageAppliedTo, this.percentage));
this.amountOutstanding = calculateOutstanding(); this.amountOutstanding = calculateOutstanding();
break; break;
case PERCENT_OF_AMOUNT_AND_INTEREST: case PERCENT_OF_AMOUNT_AND_INTEREST:
@@ -313,7 +321,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
case PERCENT_OF_AMOUNT: case PERCENT_OF_AMOUNT:
this.percentage = newValue; this.percentage = newValue;
this.amountPercentageAppliedTo = loanPrincipal; this.amountPercentageAppliedTo = loanPrincipal;
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage); this.amount = minimumAndMaximumCap(percentageOf(this.amountPercentageAppliedTo, this.percentage));
this.amountOutstanding = calculateOutstanding(); this.amountOutstanding = calculateOutstanding();
break; break;
case PERCENT_OF_AMOUNT_AND_INTEREST: case PERCENT_OF_AMOUNT_AND_INTEREST:
@@ -393,10 +401,34 @@ public class LoanCharge extends AbstractPersistable<Long> {
final BigDecimal multiplicand = percentage.divide(BigDecimal.valueOf(100l), mc); final BigDecimal multiplicand = percentage.divide(BigDecimal.valueOf(100l), mc);
percentageOf = value.multiply(multiplicand, mc); percentageOf = value.multiply(multiplicand, mc);
} }
return percentageOf; 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() { public BigDecimal amount() {
return this.amount; return this.amount;
} }
@@ -443,6 +475,14 @@ public class LoanCharge extends AbstractPersistable<Long> {
return this.waived; return this.waived;
} }
public BigDecimal getMinCap() {
return this.minCap;
}
public BigDecimal getMaxCap() {
return this.maxCap;
}
public boolean isPaidOrPartiallyPaid(final MonetaryCurrency currency) { public boolean isPaidOrPartiallyPaid(final MonetaryCurrency currency) {
final Money amountWaivedOrWrittenOff = getAmountWaived(currency).plus(getAmountWrittenOff(currency)); final Money amountWaivedOrWrittenOff = getAmountWaived(currency).plus(getAmountWrittenOff(currency));
@@ -58,6 +58,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
+ "lc.charge_payment_mode_enum as chargePaymentMode, " + "lc.charge_payment_mode_enum as chargePaymentMode, "
+ "lc.is_paid_derived as paid, " + "lc.is_paid_derived as paid, "
+ "lc.waived as waied, " + "lc.waived as waied, "
+ "lc.min_cap as minCap, lc.max_cap as maxCap, "
+ "c.currency_code as currencyCode, oc.name as currencyName, " + "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.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 "
@@ -102,10 +103,12 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
final EnumOptionData paymentMode = ChargeEnumerations.chargePaymentMode(chargePaymentMode); final EnumOptionData paymentMode = ChargeEnumerations.chargePaymentMode(chargePaymentMode);
final boolean paid = rs.getBoolean("paid"); final boolean paid = rs.getBoolean("paid");
final boolean waived = rs.getBoolean("waied"); 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, return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding,
chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty, paymentMode, chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty, paymentMode,
paid, waived, null); paid, waived, null,minCap,maxCap);
} }
} }