This is an automated email from the ASF dual-hosted git repository.
ptuomola pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 4a4cbf1 FINERACT-1374:Withdrawal-Fee-Scheme
4a4cbf1 is described below
commit 4a4cbf11be00b651d29937e774544282b73d5c09
Author: rrpawar96 <[email protected]>
AuthorDate: Fri Oct 29 16:24:40 2021 +0530
FINERACT-1374:Withdrawal-Fee-Scheme
---
.../fineract/portfolio/charge/data/ChargeData.java | 77 +++++++++++------
.../fineract/portfolio/charge/domain/Charge.java | 93 ++++++++++++++++++++-
...geDefinitionCommandFromApiJsonDeserializer.java | 57 +++++++++++++
.../service/ChargeReadPlatformServiceImpl.java | 12 ++-
...hargeWritePlatformServiceJpaRepositoryImpl.java | 5 +-
.../savings/data/SavingsAccountChargeData.java | 35 +++++++-
.../portfolio/savings/domain/SavingsAccount.java | 96 +++++++++++++++++++++-
.../savings/domain/SavingsAccountCharge.java | 43 ++++++++++
...avingsAccountChargeReadPlatformServiceImpl.java | 9 +-
...countWritePlatformServiceJpaRepositoryImpl.java | 4 +
.../V271_1__withdrawal_charges_discount.sql | 40 +++++++++
11 files changed, 428 insertions(+), 43 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeData.java
index 684d88e..d070c3a 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeData.java
@@ -30,6 +30,7 @@ import
org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
+import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountChargeData;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
@@ -43,6 +44,10 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
private final String name;
private final boolean active;
private final boolean penalty;
+ private final boolean freeWithdrawal;
+ private final Integer freeWithdrawalChargeFrequency;
+ private final Integer restartFrequency;
+ private final Integer restartFrequencyEnum;
private final CurrencyData currency;
private final BigDecimal amount;
private final EnumOptionData chargeTimeType;
@@ -94,8 +99,8 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
final GLAccountData account = null;
final TaxGroupData taxGroupData = null;
- return new ChargeData(null, null, null, null, null, null, null, null,
false, false, taxGroupData, currencyOptions,
- chargeCalculationTypeOptions, chargeAppliesToOptions,
chargeTimeTypeOptions, chargePaymentModeOptions,
+ return new ChargeData(null, null, null, null, null, null, null, null,
false, false, false, null, null, null, taxGroupData,
+ currencyOptions, chargeCalculationTypeOptions,
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions,
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
savingsChargeCalculationTypeOptions,
savingsChargeTimeTypeOptions,
clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, null, null,
null, null, null,
feeFrequencyOptions, account, incomeOrLiabilityAccountOptions,
taxGroupOptions, shareChargeCalculationTypeOptions,
@@ -104,7 +109,8 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
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, charge.taxGroup,
+ charge.chargeCalculationType, charge.chargePaymentMode,
charge.penalty, charge.active, charge.freeWithdrawal,
+ charge.freeWithdrawalChargeFrequency, charge.restartFrequency,
charge.restartFrequencyEnum, charge.taxGroup,
template.currencyOptions,
template.chargeCalculationTypeOptions, template.chargeAppliesToOptions,
template.chargeTimeTypeOptions,
template.chargePaymetModeOptions, template.loanChargeCalculationTypeOptions,
template.loanChargeTimeTypeOptions,
template.savingsChargeCalculationTypeOptions,
template.savingsChargeTimeTypeOptions,
@@ -118,7 +124,8 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
public static ChargeData instance(final Long id, final String name, final
BigDecimal amount, final CurrencyData currency,
final EnumOptionData chargeTimeType, final EnumOptionData
chargeAppliesTo, final EnumOptionData chargeCalculationType,
final EnumOptionData chargePaymentMode, final MonthDay
feeOnMonthDay, final Integer feeInterval, final boolean penalty,
- final boolean active, final BigDecimal minCap, final BigDecimal
maxCap, final EnumOptionData feeFrequency,
+ final boolean active, final boolean freeWithdrawal, final Integer
freeWithdrawalChargeFrequency, final Integer restartFrequency,
+ final Integer restartFrequencyEnum, final BigDecimal minCap, final
BigDecimal maxCap, final EnumOptionData feeFrequency,
final GLAccountData accountData, TaxGroupData taxGroupData) {
final Collection<CurrencyData> currencyOptions = null;
@@ -141,12 +148,13 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
final List<GLAccountData> expenseAccountOptions = null;
final List<GLAccountData> assetAccountOptions = null;
return new ChargeData(id, name, amount, currency, chargeTimeType,
chargeAppliesTo, chargeCalculationType, chargePaymentMode,
- penalty, active, taxGroupData, currencyOptions,
chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
- chargePaymentModeOptions, loansChargeCalculationTypeOptions,
loansChargeTimeTypeOptions,
- savingsChargeCalculationTypeOptions,
savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions,
- clientChargeTimeTypeOptions, feeOnMonthDay, feeInterval,
minCap, maxCap, feeFrequency, feeFrequencyOptions, accountData,
- incomeOrLiabilityAccountOptions, taxGroupOptions,
shareChargeCalculationTypeOptions, shareChargeTimeTypeOptions,
- accountMappingForChargeConfig, expenseAccountOptions,
assetAccountOptions);
+ penalty, active, freeWithdrawal,
freeWithdrawalChargeFrequency, restartFrequency, restartFrequencyEnum,
taxGroupData,
+ currencyOptions, chargeCalculationTypeOptions,
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions,
+ loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
savingsChargeCalculationTypeOptions,
+ savingsChargeTimeTypeOptions,
clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeOnMonthDay,
feeInterval,
+ minCap, maxCap, feeFrequency, feeFrequencyOptions,
accountData, incomeOrLiabilityAccountOptions, taxGroupOptions,
+ shareChargeCalculationTypeOptions, shareChargeTimeTypeOptions,
accountMappingForChargeConfig, expenseAccountOptions,
+ assetAccountOptions);
}
public static ChargeData lookup(final Long id, final String name, final
boolean isPenalty) {
@@ -160,6 +168,12 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
final Integer feeInterval = null;
final Boolean penalty = isPenalty;
final Boolean active = false;
+ final Boolean freeWithdrawal = false;
+ final Integer freeWithdrawalChargeFrequency = null;
+ final Integer restartFrequency = null;
+ final Integer restartFrequencyEnum = null;
+ final Boolean isPaymentType = false;
+ final PaymentTypeData paymentTypeOptions = null;
final BigDecimal minCap = null;
final BigDecimal maxCap = null;
final Collection<CurrencyData> currencyOptions = null;
@@ -186,25 +200,27 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
final List<GLAccountData> assetAccountOptions = null;
return new ChargeData(id, name, amount, currency, chargeTimeType,
chargeAppliesTo, chargeCalculationType, chargePaymentMode,
- penalty, active, taxGroupData, currencyOptions,
chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
- chargePaymentModeOptions, loansChargeCalculationTypeOptions,
loansChargeTimeTypeOptions,
- savingsChargeCalculationTypeOptions,
savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions,
- clientChargeTimeTypeOptions, feeOnMonthDay, feeInterval,
minCap, maxCap, feeFrequency, feeFrequencyOptions, account,
- incomeOrLiabilityAccountOptions, taxGroupOptions,
shareChargeCalculationTypeOptions, shareChargeTimeTypeOptions,
- accountMappingForChargeConfig, expenseAccountOptions,
assetAccountOptions);
+ penalty, active, freeWithdrawal,
freeWithdrawalChargeFrequency, restartFrequency, restartFrequencyEnum,
taxGroupData,
+ currencyOptions, chargeCalculationTypeOptions,
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions,
+ loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
savingsChargeCalculationTypeOptions,
+ savingsChargeTimeTypeOptions,
clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeOnMonthDay,
feeInterval,
+ minCap, maxCap, feeFrequency, feeFrequencyOptions, account,
incomeOrLiabilityAccountOptions, taxGroupOptions,
+ shareChargeCalculationTypeOptions, shareChargeTimeTypeOptions,
accountMappingForChargeConfig, expenseAccountOptions,
+ assetAccountOptions);
}
private ChargeData(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 boolean penalty,
final boolean active, final TaxGroupData taxGroupData,
- final Collection<CurrencyData> currencyOptions, final
List<EnumOptionData> chargeCalculationTypeOptions,
- final List<EnumOptionData> chargeAppliesToOptions, final
List<EnumOptionData> chargeTimeTypeOptions,
- final List<EnumOptionData> chargePaymentModeOptions, final
List<EnumOptionData> loansChargeCalculationTypeOptions,
- final List<EnumOptionData> loansChargeTimeTypeOptions, final
List<EnumOptionData> savingsChargeCalculationTypeOptions,
- final List<EnumOptionData> savingsChargeTimeTypeOptions, final
List<EnumOptionData> clientChargeCalculationTypeOptions,
- final List<EnumOptionData> clientChargeTimeTypeOptions, final
MonthDay feeOnMonthDay, final Integer feeInterval,
- final BigDecimal minCap, final BigDecimal maxCap, final
EnumOptionData feeFrequency,
- final List<EnumOptionData> feeFrequencyOptions, final
GLAccountData account,
+ final EnumOptionData chargePaymentMode, final boolean penalty,
final boolean active, final boolean freeWithdrawal,
+ final Integer freeWithdrawalChargeFrequency, final Integer
restartFrequency, final Integer restartFrequencyEnum,
+ final TaxGroupData taxGroupData, final Collection<CurrencyData>
currencyOptions,
+ final List<EnumOptionData> chargeCalculationTypeOptions, final
List<EnumOptionData> chargeAppliesToOptions,
+ final List<EnumOptionData> chargeTimeTypeOptions, final
List<EnumOptionData> chargePaymentModeOptions,
+ final List<EnumOptionData> loansChargeCalculationTypeOptions,
final List<EnumOptionData> loansChargeTimeTypeOptions,
+ final List<EnumOptionData> savingsChargeCalculationTypeOptions,
final List<EnumOptionData> savingsChargeTimeTypeOptions,
+ final List<EnumOptionData> clientChargeCalculationTypeOptions,
final List<EnumOptionData> clientChargeTimeTypeOptions,
+ final MonthDay feeOnMonthDay, final Integer feeInterval, final
BigDecimal minCap, final BigDecimal maxCap,
+ final EnumOptionData feeFrequency, final List<EnumOptionData>
feeFrequencyOptions, final GLAccountData account,
final Map<String, List<GLAccountData>>
incomeOrLiabilityAccountOptions, final Collection<TaxGroupData> taxGroupOptions,
final List<EnumOptionData> shareChargeCalculationTypeOptions,
final List<EnumOptionData> shareChargeTimeTypeOptions,
final String accountMappingForChargeConfig, final
List<GLAccountData> expenseAccountOptions,
@@ -221,6 +237,10 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
this.feeOnMonthDay = feeOnMonthDay;
this.penalty = penalty;
this.active = active;
+ this.freeWithdrawal = freeWithdrawal;
+ this.freeWithdrawalChargeFrequency = freeWithdrawalChargeFrequency;
+ this.restartFrequency = restartFrequency;
+ this.restartFrequencyEnum = restartFrequencyEnum;
this.minCap = minCap;
this.maxCap = maxCap;
this.currencyOptions = currencyOptions;
@@ -294,12 +314,17 @@ public final class ChargeData implements
Comparable<ChargeData>, Serializable {
final Collection<ChargeData> chargeOptions = null;
final LocalDate dueAsOfDate = null;
final Boolean isActive = null;
+ final Boolean isFreeWithdrawal = null;
+ final Integer freeWithdrawalChargeFrequency = null;
+ final Integer restartFrequency = null;
+ final Integer restartFrequencyEnum = null;
+
final LocalDate inactivationDate = null;
return SavingsAccountChargeData.instance(savingsChargeId, this.id,
savingsAccountId, this.name, this.currency, this.amount,
amountPaid, amountWaived, amountWrittenOff, amountOutstanding,
this.chargeTimeType, dueAsOfDate, this.chargeCalculationType,
percentage, amountPercentageAppliedTo, chargeOptions,
this.penalty, this.feeOnMonthDay, this.feeInterval, isActive,
- inactivationDate);
+ isFreeWithdrawal, freeWithdrawalChargeFrequency,
restartFrequency, restartFrequencyEnum, inactivationDate);
}
public ShareAccountChargeData toShareAccountChargeData() {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java
index 2078802..670db81 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java
@@ -48,6 +48,7 @@ import
org.apache.fineract.portfolio.charge.exception.ChargeDueAtDisbursementCan
import
org.apache.fineract.portfolio.charge.exception.ChargeMustBePenaltyException;
import
org.apache.fineract.portfolio.charge.exception.ChargeParameterUpdateNotSupportedException;
import org.apache.fineract.portfolio.charge.service.ChargeEnumerations;
+import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
@@ -103,6 +104,18 @@ public class Charge extends AbstractPersistableCustom {
@Column(name = "fee_frequency", nullable = true)
private Integer feeFrequency;
+ @Column(name = "is_free_withdrawal", nullable = false)
+ private boolean enableFreeWithdrawal;
+
+ @Column(name = "free_withdrawal_charge_frequency", nullable = true)
+ private Integer freeWithdrawalFrequency;
+
+ @Column(name = "restart_frequency", nullable = true)
+ private Integer restartFrequency;
+
+ @Column(name = "restart_frequency_enum", nullable = true)
+ private Integer restartFrequencyEnum;
+
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "income_or_liability_account_id")
private GLAccount account;
@@ -112,6 +125,7 @@ public class Charge extends AbstractPersistableCustom {
private TaxGroup taxGroup;
public static Charge fromJson(final JsonCommand command, final GLAccount
account, final TaxGroup taxGroup) {
+
final String name = command.stringValueOfParameterNamed("name");
final BigDecimal amount =
command.bigDecimalValueOfParameterNamed("amount");
final String currencyCode =
command.stringValueOfParameterNamed("currencyCode");
@@ -132,8 +146,23 @@ public class Charge extends AbstractPersistableCustom {
final BigDecimal maxCap =
command.bigDecimalValueOfParameterNamed("maxCap");
final Integer feeFrequency =
command.integerValueOfParameterNamed("feeFrequency");
+ boolean enableFreeWithdrawalCharge = false;
+ enableFreeWithdrawalCharge =
command.booleanPrimitiveValueOfParameterNamed("enableFreeWithdrawalCharge");
+
+ Integer freeWithdrawalFrequency = null;
+ Integer restartCountFrequency = null;
+ PeriodFrequencyType countFrequencyType = null;
+
+ if (enableFreeWithdrawalCharge) {
+ freeWithdrawalFrequency =
command.integerValueOfParameterNamed("freeWithdrawalFrequency");
+ restartCountFrequency =
command.integerValueOfParameterNamed("restartCountFrequency");
+
+ countFrequencyType =
PeriodFrequencyType.fromInt(command.integerValueOfParameterNamed("countFrequencyType"));
+ }
+
return new Charge(name, amount, currencyCode, chargeAppliesTo,
chargeTimeType, chargeCalculationType, penalty, active, paymentMode,
- feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency,
account, taxGroup);
+ feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency,
enableFreeWithdrawalCharge, freeWithdrawalFrequency,
+ restartCountFrequency, countFrequencyType, account, taxGroup);
}
protected Charge() {}
@@ -141,7 +170,9 @@ public class Charge extends AbstractPersistableCustom {
private Charge(final String name, final BigDecimal amount, final String
currencyCode, final ChargeAppliesTo chargeAppliesTo,
final ChargeTimeType chargeTime, final ChargeCalculationType
chargeCalculationType, final boolean penalty, final boolean active,
final ChargePaymentMode paymentMode, final MonthDay feeOnMonthDay,
final Integer feeInterval, final BigDecimal minCap,
- final BigDecimal maxCap, final Integer feeFrequency, final
GLAccount account, final TaxGroup taxGroup) {
+ final BigDecimal maxCap, final Integer feeFrequency, final boolean
enableFreeWithdrawalCharge,
+ final Integer freeWithdrawalFrequency, final Integer
restartFrequency, final PeriodFrequencyType restartFrequencyEnum,
+ final GLAccount account, final TaxGroup taxGroup) {
this.name = name;
this.amount = amount;
this.currencyCode = currencyCode;
@@ -186,6 +217,13 @@ public class Charge extends AbstractPersistableCustom {
"savings.charge.calculation.type.percentage.allowed.only.for.withdrawal.or.NoActivity");
}
+ if (enableFreeWithdrawalCharge) {
+ this.enableFreeWithdrawal = enableFreeWithdrawalCharge;
+ this.freeWithdrawalFrequency = freeWithdrawalFrequency;
+ this.restartFrequency = restartFrequency;
+ this.restartFrequencyEnum = restartFrequencyEnum.getValue();
+ }
+
} else if (isLoanCharge()) {
if (penalty && (chargeTime.isTimeOfDisbursement() ||
chargeTime.isTrancheDisbursement())) {
@@ -201,6 +239,7 @@ public class Charge extends AbstractPersistableCustom {
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
}
}
+
if (isPercentageOfApprovedAmount()) {
this.minCap = minCap;
this.maxCap = maxCap;
@@ -291,6 +330,22 @@ public class Charge extends AbstractPersistableCustom {
return this.maxCap;
}
+ public boolean isEnableFreeWithdrawal() {
+ return this.enableFreeWithdrawal;
+ }
+
+ public Integer getFrequencyFreeWithdrawalCharge() {
+ return this.freeWithdrawalFrequency;
+ }
+
+ public Integer getRestartFrequency() {
+ return this.restartFrequency;
+ }
+
+ public Integer getRestartFrequencyEnum() {
+ return this.restartFrequencyEnum;
+ }
+
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
@@ -355,6 +410,35 @@ public class Charge extends AbstractPersistableCustom {
}
}
+ final String freeWithdrawalFrequencyParamName =
"freeWithdrawalFrequency";
+ if
(command.isChangeInIntegerParameterNamed(freeWithdrawalFrequencyParamName,
this.freeWithdrawalFrequency)) {
+ final Integer enableFreeWithdrawalChargeNewValue =
command.integerValueOfParameterNamed(freeWithdrawalFrequencyParamName);
+ actualChanges.put(freeWithdrawalFrequencyParamName,
enableFreeWithdrawalChargeNewValue);
+ this.freeWithdrawalFrequency = enableFreeWithdrawalChargeNewValue;
+ }
+
+ final String restartCountFrequencyParamName = "restartCountFrequency";
+ if
(command.isChangeInIntegerParameterNamed(restartCountFrequencyParamName,
this.restartFrequency)) {
+ final Integer restartCountFrequencyNewValue =
command.integerValueOfParameterNamed(restartCountFrequencyParamName);
+ actualChanges.put(restartCountFrequencyParamName,
restartCountFrequencyNewValue);
+ this.restartFrequency = restartCountFrequencyNewValue;
+ }
+
+ final String countFrequencyTypeParamName = "countFrequencyType";
+ if
(command.isChangeInIntegerParameterNamed(countFrequencyTypeParamName,
this.restartFrequencyEnum)) {
+ final Integer countFrequencyTypeNewValue =
command.integerValueOfParameterNamed(countFrequencyTypeParamName);
+ actualChanges.put(countFrequencyTypeParamName,
countFrequencyTypeNewValue);
+ this.restartFrequencyEnum =
ChargeTimeType.fromInt(countFrequencyTypeNewValue).getValue();
+ }
+
+ final String enableFreeWithdrawalChargeParamName =
"enableFreeWithdrawalCharge";
+ if
(command.isChangeInBooleanParameterNamed(enableFreeWithdrawalChargeParamName,
this.enableFreeWithdrawal)) {
+ final boolean newValue =
command.booleanPrimitiveValueOfParameterNamed(enableFreeWithdrawalChargeParamName);
+ actualChanges.put(enableFreeWithdrawalChargeParamName, newValue);
+ this.enableFreeWithdrawal = newValue;
+
+ }
+
final String chargeAppliesToParamName = "chargeAppliesTo";
if (command.isChangeInIntegerParameterNamed(chargeAppliesToParamName,
this.chargeAppliesTo)) {
/*
@@ -531,8 +615,9 @@ public class Charge extends AbstractPersistableCustom {
final CurrencyData currency = new CurrencyData(this.currencyCode,
null, 0, 0, null, null);
return ChargeData.instance(getId(), this.name, this.amount, currency,
chargeTimeType, chargeAppliesTo, chargeCalculationType,
- chargePaymentmode, getFeeOnMonthDay(), this.feeInterval,
this.penalty, this.active, this.minCap, this.maxCap,
- feeFrequencyType, accountData, taxGroupData);
+ chargePaymentmode, getFeeOnMonthDay(), this.feeInterval,
this.penalty, this.active, this.enableFreeWithdrawal,
+ this.freeWithdrawalFrequency, this.restartFrequency,
this.restartFrequencyEnum, this.minCap, this.maxCap, feeFrequencyType,
+ accountData, taxGroupData);
}
public Integer getChargePaymentMode() {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java
index 1fa940a..e5d35e8 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java
@@ -54,6 +54,7 @@ public final class
ChargeDefinitionCommandFromApiJsonDeserializer {
private final Set<String> supportedParameters = new
HashSet<>(Arrays.asList("name", "amount", "locale", "currencyCode",
"currencyOptions", "chargeAppliesTo", "chargeTimeType",
"chargeCalculationType", "chargeCalculationTypeOptions", "penalty",
"active", "chargePaymentMode", "feeOnMonthDay", "feeInterval",
"monthDayFormat", "minCap", "maxCap", "feeFrequency",
+ "enableFreeWithdrawalCharge", "freeWithdrawalFrequency",
"restartCountFrequency", "countFrequencyType",
ChargesApiConstants.glAccountIdParamName,
ChargesApiConstants.taxGroupIdParamName));
private final FromJsonHelper fromApiJsonHelper;
@@ -91,6 +92,28 @@ public final class
ChargeDefinitionCommandFromApiJsonDeserializer {
final Integer feeFrequency =
this.fromApiJsonHelper.extractIntegerNamed("feeFrequency", element,
Locale.getDefault());
baseDataValidator.reset().parameter("feeFrequency").value(feeFrequency).inMinMaxRange(0,
3);
+ if
(this.fromApiJsonHelper.parameterExists("enableFreeWithdrawalCharge", element))
{
+
+ final Boolean enableFreeWithdrawalCharge =
this.fromApiJsonHelper.extractBooleanNamed("enableFreeWithdrawalCharge",
element);
+
baseDataValidator.reset().parameter("enableFreeWithdrawalCharge").value(enableFreeWithdrawalCharge).notNull();
+
+ if (enableFreeWithdrawalCharge) {
+
+ final Integer freeWithdrawalFrequency =
this.fromApiJsonHelper.extractIntegerNamed("freeWithdrawalFrequency", element,
+ Locale.getDefault());
+
baseDataValidator.reset().parameter("freeWithdrawalFrequency").value(freeWithdrawalFrequency).integerGreaterThanZero();
+
+ final Integer restartCountFrequency =
this.fromApiJsonHelper.extractIntegerNamed("restartCountFrequency", element,
+ Locale.getDefault());
+
baseDataValidator.reset().parameter("restartCountFrequency").value(restartCountFrequency).integerGreaterThanZero();
+
+ final Integer countFrequencyType =
this.fromApiJsonHelper.extractIntegerNamed("countFrequencyType", element,
+ Locale.getDefault());
+
baseDataValidator.reset().parameter("countFrequencyType").value(countFrequencyType);
+
+ }
+ }
+
if (feeFrequency != null) {
baseDataValidator.reset().parameter("feeInterval").value(feeInterval).notNull();
}
@@ -155,6 +178,7 @@ public final class
ChargeDefinitionCommandFromApiJsonDeserializer {
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForSavings());
}
+
} else if (appliesTo.isClientCharge()) {
// client applicable validation
final Integer chargeTimeType =
this.fromApiJsonHelper.extractIntegerSansLocaleNamed("chargeTimeType", element);
@@ -277,6 +301,39 @@ public final class
ChargeDefinitionCommandFromApiJsonDeserializer {
.isOneOfTheseValues(ChargeAppliesTo.validValues());
}
+ Boolean enableFreeWithdrawalCharge = false;
+ if
(this.fromApiJsonHelper.parameterExists("enableFreeWithdrawalCharge", element))
{
+ enableFreeWithdrawalCharge =
this.fromApiJsonHelper.extractBooleanNamed("enableFreeWithdrawalCharge",
element);
+
baseDataValidator.reset().parameter("enableFreeWithdrawalCharge").value(enableFreeWithdrawalCharge).notNull();
+
+ if (enableFreeWithdrawalCharge) {
+
+ final Integer freeWithdrawalFrequency =
this.fromApiJsonHelper.extractIntegerNamed("freeWithdrawalFrequency", element,
+ Locale.getDefault());
+
baseDataValidator.reset().parameter("freeWithdrawalFrequency").value(freeWithdrawalFrequency).integerGreaterThanZero();
+
+ final Integer restartCountFrequency =
this.fromApiJsonHelper.extractIntegerNamed("restartCountFrequency", element,
+ Locale.getDefault());
+
baseDataValidator.reset().parameter("restartCountFrequency").value(restartCountFrequency).integerGreaterThanZero();
+
+ final Integer countFrequencyType =
this.fromApiJsonHelper.extractIntegerNamed("countFrequencyType", element,
+ Locale.getDefault());
+
baseDataValidator.reset().parameter("countFrequencyType").value(countFrequencyType);
+ }
+ }
+
+ if (this.fromApiJsonHelper.parameterExists("chargeAppliesTo",
element)) {
+ final Integer chargeAppliesTo =
this.fromApiJsonHelper.extractIntegerSansLocaleNamed("chargeAppliesTo",
element);
+
baseDataValidator.reset().parameter("chargeAppliesTo").value(chargeAppliesTo).notNull()
+ .isOneOfTheseValues(ChargeAppliesTo.validValues());
+ }
+
+ if (this.fromApiJsonHelper.parameterExists("chargeAppliesTo",
element)) {
+ final Integer chargeAppliesTo =
this.fromApiJsonHelper.extractIntegerSansLocaleNamed("chargeAppliesTo",
element);
+
baseDataValidator.reset().parameter("chargeAppliesTo").value(chargeAppliesTo).notNull()
+ .isOneOfTheseValues(ChargeAppliesTo.validValues());
+ }
+
if (this.fromApiJsonHelper.parameterExists("chargeTimeType", element))
{
final Integer chargeTimeType =
this.fromApiJsonHelper.extractIntegerSansLocaleNamed("chargeTimeType", element);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformServiceImpl.java
index 9bf0703..26f46ea 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformServiceImpl.java
@@ -287,7 +287,8 @@ public class ChargeReadPlatformServiceImpl implements
ChargeReadPlatformService
+ "c.charge_applies_to_enum as chargeAppliesTo,
c.charge_time_enum as chargeTime, "
+ "c.charge_payment_mode_enum as chargePaymentMode, "
+ "c.charge_calculation_enum as chargeCalculation,
c.is_penalty as penalty, "
- + "c.is_active as active, oc.name as currencyName,
oc.decimal_places as currencyDecimalPlaces, "
+ + "c.is_active as active, c.is_free_withdrawal as
isFreeWithdrawal, c.free_withdrawal_charge_frequency as
freeWithdrawalChargeFrequency, c.restart_frequency as restartFrequency,
c.restart_frequency_enum as restartFrequencyEnum,"
+ + "oc.name as currencyName, oc.decimal_places as
currencyDecimalPlaces, "
+ "oc.currency_multiplesof as inMultiplesOf,
oc.display_symbol as currencyDisplaySymbol, "
+ "oc.internationalized_name_code as currencyNameCode,
c.fee_on_day as feeOnDay, c.fee_on_month as feeOnMonth, "
+ "c.fee_interval as feeInterval, c.fee_frequency as
feeFrequency,c.min_cap as minCap,c.max_cap as maxCap, "
@@ -372,9 +373,14 @@ public class ChargeReadPlatformServiceImpl implements
ChargeReadPlatformService
taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName);
}
+ final boolean isFreeWithdrawal = rs.getBoolean("isFreeWithdrawal");
+ final int freeWithdrawalChargeFrequency =
rs.getInt("freeWithdrawalChargeFrequency");
+ final int restartFrequency = rs.getInt("restartFrequency");
+ final int restartFrequencyEnum = rs.getInt("restartFrequencyEnum");
+
return ChargeData.instance(id, name, amount, currency,
chargeTimeType, chargeAppliesToType, chargeCalculationType,
- chargePaymentMode, feeOnMonthDay, feeInterval, penalty,
active, minCap, maxCap, feeFrequencyType, glAccountData,
- taxGroupData);
+ chargePaymentMode, feeOnMonthDay, feeInterval, penalty,
active, isFreeWithdrawal, freeWithdrawalChargeFrequency,
+ restartFrequency, restartFrequencyEnum, minCap, maxCap,
feeFrequencyType, glAccountData, taxGroupData);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java
index 9a611de..22959c0 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java
@@ -42,6 +42,7 @@ import
org.apache.fineract.portfolio.charge.exception.ChargeNotFoundException;
import
org.apache.fineract.portfolio.charge.serialization.ChargeDefinitionCommandFromApiJsonDeserializer;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
+import
org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepositoryWrapper;
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
import org.apache.fineract.portfolio.tax.domain.TaxGroupRepositoryWrapper;
import org.slf4j.Logger;
@@ -67,13 +68,14 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl
implements ChargeWriteP
private final FineractEntityAccessUtil fineractEntityAccessUtil;
private final GLAccountRepositoryWrapper glAccountRepository;
private final TaxGroupRepositoryWrapper taxGroupRepository;
+ private final PaymentTypeRepositoryWrapper paymentTyperepositoryWrapper;
@Autowired
public ChargeWritePlatformServiceJpaRepositoryImpl(final
PlatformSecurityContext context,
final ChargeDefinitionCommandFromApiJsonDeserializer
fromApiJsonDeserializer, final ChargeRepository chargeRepository,
final LoanProductRepository loanProductRepository, final
RoutingDataSource dataSource,
final FineractEntityAccessUtil fineractEntityAccessUtil, final
GLAccountRepositoryWrapper glAccountRepository,
- final TaxGroupRepositoryWrapper taxGroupRepository) {
+ final TaxGroupRepositoryWrapper taxGroupRepository, final
PaymentTypeRepositoryWrapper paymentTyperepositoryWrapper) {
this.context = context;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.dataSource = dataSource;
@@ -83,6 +85,7 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl
implements ChargeWriteP
this.fineractEntityAccessUtil = fineractEntityAccessUtil;
this.glAccountRepository = glAccountRepository;
this.taxGroupRepository = taxGroupRepository;
+ this.paymentTyperepositoryWrapper = paymentTyperepositoryWrapper;
}
@Transactional
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountChargeData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountChargeData.java
index 4ea79eb..715f3f4 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountChargeData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountChargeData.java
@@ -74,6 +74,14 @@ public class SavingsAccountChargeData implements
Serializable {
private final Boolean isActive;
+ private final Boolean isFreeWithdrawal;
+
+ private final Integer freeWithdrawalChargeFrequency;
+
+ private final Integer restartFrequency;
+
+ private final Integer restartFrequencyEnum;
+
private final LocalDate inactivationDate;
private final Collection<ChargeData> chargeOptions;
@@ -101,6 +109,10 @@ public class SavingsAccountChargeData implements
Serializable {
this.isActive = null;
this.inactivationDate = null;
this.chargeOptions = null;
+ this.isFreeWithdrawal = null;
+ this.freeWithdrawalChargeFrequency = null;
+ this.restartFrequency = null;
+ this.restartFrequencyEnum = null;
}
public static SavingsAccountChargeData template(final
Collection<ChargeData> chargeOptions) {
@@ -123,11 +135,17 @@ public class SavingsAccountChargeData implements
Serializable {
final MonthDay feeOnMonthDay = null;
final Integer feeInterval = null;
final Boolean isActive = null;
+ final Boolean isFreeWithdrawal = null;
+ final Integer freeWithdrawalChargeFrequency = null;
+ final Integer restartFrequency = null;
+ final Integer restartFrequencyEnum = null;
+
final LocalDate inactivationDate = null;
return new SavingsAccountChargeData(id, chargeId, accountId, name,
chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
amountPercentageAppliedTo, currency, amount, amountPaid,
amountWaived, amountWrittenOff, amountOutstanding, chargeOptions,
- penalty, feeOnMonthDay, feeInterval, isActive,
inactivationDate);
+ penalty, feeOnMonthDay, feeInterval, isActive,
isFreeWithdrawal, freeWithdrawalChargeFrequency, restartFrequency,
+ restartFrequencyEnum, inactivationDate);
}
public static SavingsAccountChargeData instance(final Long id, final Long
chargeId, final Long accountId, final String name,
@@ -135,11 +153,14 @@ public class SavingsAccountChargeData implements
Serializable {
final BigDecimal amountWrittenOff, final BigDecimal
amountOutstanding, final EnumOptionData chargeTimeType,
final LocalDate dueAsOfDate, final EnumOptionData
chargeCalculationType, final BigDecimal percentage,
final BigDecimal amountPercentageAppliedTo, final
Collection<ChargeData> chargeOptions, final boolean penalty,
- final MonthDay feeOnMonthDay, final Integer feeInterval, final
Boolean isActive, final LocalDate inactivationDate) {
+ final MonthDay feeOnMonthDay, final Integer feeInterval, final
Boolean isActive, final Boolean isFreeWithdrawal,
+ final Integer freeWithdrawalChargeFrequency, final Integer
restartFrequency, final Integer restartFrequencyEnum,
+ final LocalDate inactivationDate) {
return new SavingsAccountChargeData(id, chargeId, accountId, name,
chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
amountPercentageAppliedTo, currency, amount, amountPaid,
amountWaived, amountWrittenOff, amountOutstanding, chargeOptions,
- penalty, feeOnMonthDay, feeInterval, isActive,
inactivationDate);
+ penalty, feeOnMonthDay, feeInterval, isActive,
isFreeWithdrawal, freeWithdrawalChargeFrequency, restartFrequency,
+ restartFrequencyEnum, inactivationDate);
}
private SavingsAccountChargeData(final Long id, final Long chargeId, final
Long accountId, final String name,
@@ -147,7 +168,9 @@ public class SavingsAccountChargeData implements
Serializable {
final BigDecimal percentage, final BigDecimal
amountPercentageAppliedTo, final CurrencyData currency, final BigDecimal amount,
final BigDecimal amountPaid, final BigDecimal amountWaived, final
BigDecimal amountWrittenOff,
final BigDecimal amountOutstanding, final Collection<ChargeData>
chargeOptions, final boolean penalty,
- final MonthDay feeOnMonthDay, final Integer feeInterval, final
Boolean isActive, final LocalDate inactivationDate) {
+ final MonthDay feeOnMonthDay, final Integer feeInterval, final
Boolean isActive, final Boolean isFreeWithdrawal,
+ final Integer freeWithdrawalChargeFrequency, final Integer
restartFrequency, final Integer restartFrequencyEnum,
+ final LocalDate inactivationDate) {
this.id = id;
this.chargeId = chargeId;
this.accountId = accountId;
@@ -170,6 +193,10 @@ public class SavingsAccountChargeData implements
Serializable {
this.feeInterval = feeInterval;
this.isActive = isActive;
this.inactivationDate = inactivationDate;
+ this.isFreeWithdrawal = isFreeWithdrawal;
+ this.freeWithdrawalChargeFrequency = freeWithdrawalChargeFrequency;
+ this.restartFrequency = restartFrequency;
+ this.restartFrequencyEnum = restartFrequencyEnum;
}
private BigDecimal getAmountOrPercentage() {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
index 3ffbc25..bc0301e 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
@@ -36,6 +36,7 @@ import com.google.gson.JsonArray;
import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
+import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
@@ -50,6 +51,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
@@ -92,6 +94,7 @@ import
org.apache.fineract.portfolio.charge.exception.SavingsAccountChargeNotFou
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.group.domain.Group;
+import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.portfolio.savings.DepositAccountType;
import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
@@ -1038,7 +1041,8 @@ public class SavingsAccount extends
AbstractPersistableCustom {
if (applyWithdrawFee) {
// auto pay withdrawal fee
- payWithdrawalFee(transactionDTO.getTransactionAmount(),
transactionDTO.getTransactionDate(), transactionDTO.getAppUser());
+ payWithdrawalFee(transactionDTO.getTransactionAmount(),
transactionDTO.getTransactionDate(), transactionDTO.getAppUser(),
+ transactionDTO.getPaymentDetail());
}
final Money transactionAmountMoney = Money.of(this.currency,
transactionDTO.getTransactionAmount());
@@ -1066,15 +1070,99 @@ public class SavingsAccount extends
AbstractPersistableCustom {
return result;
}
- private void payWithdrawalFee(final BigDecimal transactionAmount, final
LocalDate transactionDate, final AppUser user) {
+ private void payWithdrawalFee(final BigDecimal transactionAmount, final
LocalDate transactionDate, final AppUser user,
+ final PaymentDetail paymentDetail) {
+
for (SavingsAccountCharge charge : this.charges()) {
+
if (charge.isWithdrawalFee() && charge.isActive()) {
- charge.updateWithdralFeeAmount(transactionAmount);
- this.payCharge(charge,
charge.getAmountOutstanding(this.getCurrency()), transactionDate, user);
+ if (charge.getFreeWithdrawalCount() == null) {
+ charge.setFreeWithdrawalCount(0);
+ }
+
+ if (charge.isEnableFreeWithdrawal()) {
+ resetFreeChargeDaysCount(charge, transactionAmount,
transactionDate, user);
+
+ } else {
+ charge.updateWithdralFeeAmount(transactionAmount);
+ this.payCharge(charge,
charge.getAmountOutstanding(this.getCurrency()), transactionDate, user);
+ }
}
+
}
}
+ private void resetFreeChargeDaysCount(SavingsAccountCharge charge, final
BigDecimal transactionAmount, final LocalDate transactionDate,
+ final AppUser user) {
+ Date resetDate = charge.getResetChargeDate();
+
+ Integer restartPeriod = charge.getRestartFrequency();
+ if (charge.getRestartFrequencyEnum() == 2) { // calculation for months
+ Date currentDate = new Date();
+ LocalDate localDate =
currentDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ Integer currentMonth = localDate.getMonthValue();
+
+ LocalDate resetLocalDate = null;
+ if (resetDate == null) {
+ resetLocalDate =
this.activatedOnDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ } else {
+ resetLocalDate =
resetDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+ Integer resetMonth = resetLocalDate.getMonthValue();
+
+ LocalDate gapIntervalMonth =
resetLocalDate.plusMonths(restartPeriod);
+ Integer gapMonth = gapIntervalMonth.getMonthValue();
+
+ Integer resetYear = resetLocalDate.getYear();
+ Integer currentYear = localDate.getYear();
+
+ YearMonth gapYearMonth = YearMonth.from(gapIntervalMonth);
+ YearMonth localYearMonth = YearMonth.from(localDate);
+ if (localYearMonth.isBefore(gapYearMonth)) {
+ countValidation(charge, transactionAmount, transactionDate,
user);
+ } else {
+ discountCharge(1, charge);
+ }
+ } else { // calculation for days
+ Long completedDays = null;
+ Long days = null;
+
+ if (resetDate == null) {
+ completedDays = DateUtils.getDateOfTenant().getTime() -
this.activatedOnDate.getTime();
+ days = TimeUnit.DAYS.convert(completedDays,
TimeUnit.MILLISECONDS);
+ } else {
+ completedDays = DateUtils.getDateOfTenant().getTime() -
resetDate.getTime();
+ days = TimeUnit.DAYS.convert(completedDays,
TimeUnit.MILLISECONDS);
+ }
+
+ Integer totalDays = days.intValue();
+
+ if (totalDays < restartPeriod) {
+ countValidation(charge, transactionAmount, transactionDate,
user);
+ } else {
+ discountCharge(1, charge);
+ }
+ }
+ }
+
+ private void countValidation(SavingsAccountCharge charge, final BigDecimal
transactionAmount, final LocalDate transactionDate,
+ final AppUser user) {
+ if (charge.getFreeWithdrawalCount() <
charge.getFrequencyFreeWithdrawalCharge()) {
+ final Integer count = charge.getFreeWithdrawalCount() + 1;
+ charge.setFreeWithdrawalCount(count);
+ charge.updateNoWithdrawalFee();
+ } else {
+ charge.updateWithdralFeeAmount(transactionAmount);
+ this.payCharge(charge,
charge.getAmountOutstanding(this.getCurrency()), transactionDate, user);
+ }
+ }
+
+ private void discountCharge(Integer freeWithdrawalCount,
SavingsAccountCharge charge) {
+ charge.setFreeWithdrawalCount(freeWithdrawalCount);
+ charge.setDiscountDueDate(DateUtils.getDateOfTenant());
+ charge.updateNoWithdrawalFee();
+ }
+
public boolean isBeforeLastPostingPeriod(final LocalDate transactionDate) {
boolean transactionBeforeLastInterestPosting = false;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountCharge.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountCharge.java
index 0ae6e4b..f0e8401 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountCharge.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountCharge.java
@@ -94,6 +94,13 @@ public class SavingsAccountCharge extends
AbstractPersistableCustom {
@Column(name = "charge_calculation_enum")
private Integer chargeCalculation;
+ @Column(name = "free_withdrawal_count", nullable = true)
+ private Integer freeWithdrawalCount;
+
+ @Temporal(TemporalType.DATE)
+ @Column(name = "charge_reset_date", nullable = true)
+ private Date chargeResetDate;
+
@Column(name = "calculation_percentage", scale = 6, precision = 19,
nullable = true)
private BigDecimal percentage;
@@ -666,6 +673,38 @@ public class SavingsAccountCharge extends
AbstractPersistableCustom {
return this.charge;
}
+ public boolean isEnableFreeWithdrawal() {
+ return charge.isEnableFreeWithdrawal();
+ }
+
+ public Integer getFrequencyFreeWithdrawalCharge() { // number of times
free withdrawal allowed
+ return charge.getFrequencyFreeWithdrawalCharge();
+ }
+
+ public Integer getRestartFrequency() { // numeric value of which
numeric-period, count should restart
+ return charge.getRestartFrequency();
+ }
+
+ public Integer getRestartFrequencyEnum() { // enum day/week/month for
restarting the count.
+ return charge.getRestartFrequencyEnum();
+ }
+
+ public Integer getFreeWithdrawalCount() {
+ return freeWithdrawalCount;
+ }
+
+ public void setFreeWithdrawalCount(Integer freeWithdrawalCount) {
+ this.freeWithdrawalCount = freeWithdrawalCount;
+ }
+
+ public Date getResetChargeDate() {
+ return chargeResetDate;
+ }
+
+ public void setDiscountDueDate(final Date date) {
+ this.chargeResetDate = date;
+ }
+
public SavingsAccount savingsAccount() {
return this.savingsAccount;
}
@@ -758,6 +797,10 @@ public class SavingsAccountCharge extends
AbstractPersistableCustom {
return amountOutstanding =
calculateWithdralFeeAmount(transactionAmount);
}
+ public BigDecimal updateNoWithdrawalFee() {
+ return amountOutstanding = BigDecimal.ZERO;
+ }
+
public void updateToNextDueDateFrom(final LocalDate startingDate) {
if (isAnnualFee() || isMonthlyFee() || isWeeklyFee()) {
this.dueDate =
Date.from(getNextDueDateFrom(startingDate).atStartOfDay(ZoneId.systemDefault()).toInstant());
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java
index 9416d74..0d68fc0 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java
@@ -82,6 +82,7 @@ public class SavingsAccountChargeReadPlatformServiceImpl
implements SavingsAccou
+ "sc.fee_on_month as feeOnMonth, " + "sc.fee_on_day as
feeOnDay, sc.fee_interval as feeInterval, "
+ "sc.charge_calculation_enum as chargeCalculation, "
+ "sc.is_active as isActive, sc.inactivated_on_date as
inactivationDate, "
+ + "c.is_free_withdrawal as isFreeWithdrawal,
c.free_withdrawal_charge_frequency as freeWithdrawalChargeFrequency,
c.restart_frequency as restartFrequency, c.restart_frequency_enum as
restartFrequencyEnum, "
+ "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 "
@@ -133,11 +134,17 @@ public class SavingsAccountChargeReadPlatformServiceImpl
implements SavingsAccou
final Boolean isActive = rs.getBoolean("isActive");
final LocalDate inactivationDate = JdbcSupport.getLocalDate(rs,
"inactivationDate");
+ final Boolean isFreeWithdrawal = rs.getBoolean("isFreeWithdrawal");
+ final Integer freeWithdrawalChargeFrequency =
JdbcSupport.getInteger(rs, "freeWithdrawalChargeFrequency");
+ final Integer restartFrequency = JdbcSupport.getInteger(rs,
"restartFrequency");
+ final Integer restartFrequencyEnum = JdbcSupport.getInteger(rs,
"restartFrequencyEnum");
+
final Collection<ChargeData> chargeOptions = null;
return SavingsAccountChargeData.instance(id, chargeId, accountId,
name, currency, amount, amountPaid, amountWaived,
amountWrittenOff, amountOutstanding, chargeTimeType,
dueAsOfDate, chargeCalculationType, percentageOf,
- amountPercentageAppliedTo, chargeOptions, penalty,
feeOnMonthDay, feeInterval, isActive, inactivationDate);
+ amountPercentageAppliedTo, chargeOptions, penalty,
feeOnMonthDay, feeInterval, isActive, isFreeWithdrawal,
+ freeWithdrawalChargeFrequency, restartFrequency,
restartFrequencyEnum, inactivationDate);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
index b3f0b1f..e03b897 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -1025,6 +1025,10 @@ public class
SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
final SavingsAccountCharge savingsAccountCharge =
SavingsAccountCharge.createNewFromJson(savingsAccount, chargeDefinition,
command);
+ if (chargeDefinition.isEnableFreeWithdrawal()) {
+ savingsAccountCharge.setFreeWithdrawalCount(0);
+ }
+
if (savingsAccountCharge.getDueLocalDate() != null) {
// transaction date should not be on a holiday or non working day
if
(!this.configurationDomainService.allowTransactionsOnHolidayEnabled()
diff --git
a/fineract-provider/src/main/resources/sql/migrations/core_db/V271_1__withdrawal_charges_discount.sql
b/fineract-provider/src/main/resources/sql/migrations/core_db/V271_1__withdrawal_charges_discount.sql
new file mode 100644
index 0000000..76c0db1
--- /dev/null
+++
b/fineract-provider/src/main/resources/sql/migrations/core_db/V271_1__withdrawal_charges_discount.sql
@@ -0,0 +1,40 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+
+ALTER TABLE `m_charge` ADD COLUMN `is_free_withdrawal` INT NOT NULL DEFAULT
'0' AFTER `fee_frequency`;
+
+
+ALTER TABLE `m_charge`
+ ADD COLUMN `free_withdrawal_charge_frequency` INT NULL DEFAULT '0' AFTER
`is_free_withdrawal`;
+
+
+ALTER TABLE `m_charge`
+ ADD COLUMN `restart_frequency` INT NULL DEFAULT '0' AFTER
`free_withdrawal_charge_frequency`;
+
+
+ALTER TABLE `m_charge`
+ ADD COLUMN `restart_frequency_enum` INT NULL DEFAULT '0' AFTER
`restart_frequency`;
+
+
+ALTER TABLE `m_savings_account_charge`
+ ADD COLUMN `free_withdrawal_count` INT NULL DEFAULT '0' AFTER
`fee_interval`;
+
+ALTER TABLE `m_savings_account_charge`
+ ADD COLUMN `charge_reset_date` DATE NULL DEFAULT NULL AFTER
`free_withdrawal_count`;