This is an automated email from the ASF dual-hosted git repository.
aleks pushed a commit to branch 1.8.0
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/1.8.0 by this push:
new edc734c94 FINERACT-1668: Adding Configuration for reversal transaction
(#2454)
edc734c94 is described below
commit edc734c946862e6a6818d6b6211c6fbf026316fc
Author: logoutdhaval <[email protected]>
AuthorDate: Fri Aug 5 16:36:40 2022 +0530
FINERACT-1668: Adding Configuration for reversal transaction (#2454)
Co-authored-by: Dhaval Maniyar <[email protected]>
---
.../domain/ConfigurationDomainService.java | 2 +
.../domain/ConfigurationDomainServiceJpa.java | 7 +++
.../domain/DepositAccountDomainServiceJpa.java | 11 ++--
.../savings/domain/FixedDepositAccount.java | 3 +
.../savings/domain/RecurringDepositAccount.java | 19 +++----
.../portfolio/savings/domain/SavingsAccount.java | 5 +-
.../domain/SavingsAccountDomainServiceJpa.java | 11 ++--
...countWritePlatformServiceJpaRepositoryImpl.java | 34 ++++++------
.../db/changelog/tenant/changelog-tenant.xml | 1 +
.../0026_reversals_for_reversed_transactions.xml | 37 +++++++++++++
.../ClientSavingsIntegrationTest.java | 64 ++++++++++++++++++++++
.../common/GlobalConfigurationHelper.java | 12 +++-
12 files changed, 162 insertions(+), 44 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
index 73761fbcc..14b92f646 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -116,4 +116,6 @@ public interface ConfigurationDomainService {
boolean isBusinessDateEnabled();
boolean isCOBDateAdjustmentEnabled();
+
+ boolean isReversalTransactionAllowed();
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index 6dd1a1ab8..d77071f55 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -444,4 +444,11 @@ public class ConfigurationDomainServiceJpa implements
ConfigurationDomainService
public boolean isCOBDateAdjustmentEnabled() {
return
getGlobalConfigurationPropertyData(ENABLE_AUTOMATIC_COB_DATE_ADJUSTMENT).isEnabled();
}
+
+ @Override
+ public boolean isReversalTransactionAllowed() {
+ final String propertyName =
"enable-post-reversal-txns-for-reverse-transactions";
+ final GlobalConfigurationPropertyData property =
getGlobalConfigurationPropertyData(propertyName);
+ return property.isEnabled();
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
index 85f49ef40..1f1d09bc5 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
@@ -140,7 +140,6 @@ public class DepositAccountDomainServiceJpa implements
DepositAccountDomainServi
final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
-
boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
final MathContext mc = MathContext.DECIMAL64;
@@ -348,7 +347,7 @@ public class DepositAccountDomainServiceJpa implements
DepositAccountDomainServi
final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
-
+ final boolean postReversals = false;
boolean isRegularTransaction = false;
boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
@@ -364,7 +363,7 @@ public class DepositAccountDomainServiceJpa implements
DepositAccountDomainServi
final DateTimeFormatter fmt =
DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
final LocalDate closedDate =
command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
Long savingsTransactionId = null;
-
account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, closedDate);
+
account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, closedDate, postReversals);
final BigDecimal transactionAmount = account.getAccountBalance();
final Integer onAccountClosureId =
command.integerValueOfParameterNamed(onAccountClosureIdParamName);
final DepositAccountOnClosureType onClosureType =
DepositAccountOnClosureType.fromInt(onAccountClosureId);
@@ -385,7 +384,7 @@ public class DepositAccountDomainServiceJpa implements
DepositAccountDomainServi
Integer frequency =
CalendarUtils.getInterval(calendar.getRecurrence());
frequency = frequency == -1 ? 1 : frequency;
reinvestedDeposit.generateSchedule(frequencyType, frequency,
calendar);
- reinvestedDeposit.processAccountUponActivation(fmt, user);
+ reinvestedDeposit.processAccountUponActivation(fmt, user,
postReversals);
reinvestedDeposit.updateMaturityDateAndAmount(mc,
isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth);
this.savingsAccountRepository.save(reinvestedDeposit);
@@ -520,7 +519,7 @@ public class DepositAccountDomainServiceJpa implements
DepositAccountDomainServi
final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
-
+ final boolean postReversals = false;
boolean isAccountTransfer = false;
final boolean isPreMatureClosure = true;
boolean isRegularTransaction = false;
@@ -537,7 +536,7 @@ public class DepositAccountDomainServiceJpa implements
DepositAccountDomainServi
Long savingsTransactionId = null;
// post interest
account.postPreMaturityInterest(closedDate, isPreMatureClosure,
isSavingsInterestPostingAtCurrentPeriodEnd,
- financialYearBeginningMonth);
+ financialYearBeginningMonth, postReversals);
final Integer closureTypeValue =
command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName);
DepositAccountOnClosureType closureType =
DepositAccountOnClosureType.fromInt(closureTypeValue);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java
index a306b3a9b..60eec4dc7 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java
@@ -39,6 +39,7 @@ import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
+import
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
@@ -77,6 +78,8 @@ public class FixedDepositAccount extends SavingsAccount {
@Transient
protected InterestRateChartAssembler chartAssembler;
+ @Transient
+ private ConfigurationDomainService configurationDomainService;
protected FixedDepositAccount() {
//
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java
index 98e1a4823..7d59e1825 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java
@@ -270,11 +270,11 @@ public class RecurringDepositAccount extends
SavingsAccount {
}
}
- public void updateMaturityStatus(final boolean
isSavingsInterestPostingAtCurrentPeriodEnd, final Integer
financialYearBeginningMonth) {
+ public void updateMaturityStatus(final boolean
isSavingsInterestPostingAtCurrentPeriodEnd, final Integer
financialYearBeginningMonth,
+ final boolean postReversals) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new
DataValidatorBuilder(dataValidationErrors)
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME +
SavingsApiConstants.updateMaturityDetailsAction);
-
final SavingsAccountStatusType currentStatus =
SavingsAccountStatusType.fromInt(this.status);
if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.in.active.state");
@@ -287,7 +287,7 @@ public class RecurringDepositAccount extends SavingsAccount
{
if (!this.maturityDate().isAfter(todayDate)) {
// update account status
this.status = SavingsAccountStatusType.MATURED.getValue();
- postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, todayDate);
+ postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, todayDate, postReversals);
}
}
@@ -537,7 +537,7 @@ public class RecurringDepositAccount extends SavingsAccount
{
return Money.of(this.currency, this.minRequiredOpeningBalance);
}
- protected void processAccountUponActivation(final DateTimeFormatter fmt,
final AppUser user) {
+ protected void processAccountUponActivation(final DateTimeFormatter fmt,
final AppUser user, final boolean postReversals) {
final Money minRequiredOpeningBalance = Money.of(this.currency,
this.minRequiredOpeningBalance);
final boolean backdatedTxnsAllowedTill = false;
String refNo = null;
@@ -549,7 +549,6 @@ public class RecurringDepositAccount extends SavingsAccount
{
// update existing transactions so derived balance fields are
// correct.
- boolean postReversals = false;
recalculateDailyBalances(Money.zero(this.currency),
DateUtils.getBusinessLocalDate(), backdatedTxnsAllowedTill, postReversals);
}
}
@@ -635,7 +634,7 @@ public class RecurringDepositAccount extends SavingsAccount
{
}
public void postMaturityInterest(final boolean
isSavingsInterestPostingAtCurrentPeriodEnd, final Integer
financialYearBeginningMonth,
- final LocalDate closeDate) {
+ final LocalDate closeDate, final boolean postReversals) {
LocalDate interestPostingUpToDate = maturityDate();
if (interestPostingUpToDate == null) {
interestPostingUpToDate = closeDate;
@@ -645,7 +644,6 @@ public class RecurringDepositAccount extends SavingsAccount
{
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
final boolean backdatedTxnsAllowedTill = false;
- boolean postReversals = false;
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc,
interestPostingUpToDate.minusDays(1), isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill,
postReversals);
@@ -690,7 +688,7 @@ public class RecurringDepositAccount extends SavingsAccount
{
}
public void postPreMaturityInterest(final LocalDate accountCloseDate,
final boolean isPreMatureClosure,
- final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final
Integer financialYearBeginningMonth) {
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final
Integer financialYearBeginningMonth, boolean postReversals) {
final Money interestPostedToDate = totalInterestPosted();
// calculate interest before one day of closure date
@@ -713,7 +711,6 @@ public class RecurringDepositAccount extends SavingsAccount
{
}
applyWithholdTaxForDepositAccounts(accountCloseDate,
recalucateDailyBalance, backdatedTxnsAllowedTill);
- boolean postReversals = false;
if (recalucateDailyBalance) {
// update existing transactions so derived balance fields are
// correct.
@@ -755,11 +752,11 @@ public class RecurringDepositAccount extends
SavingsAccount {
return interestOnMaturity;
}
+ @Override
public void postInterest(final MathContext mc, final LocalDate
postingDate, final boolean isInterestTransfer,
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final
Integer financialYearBeginningMonth,
- final LocalDate postInterestAson, final boolean
backdatedTxnsAllowedTill) {
+ final LocalDate postInterestAson, final boolean
backdatedTxnsAllowedTill, final boolean postReversals) {
final LocalDate interestPostingUpToDate =
interestPostingUpToDate(postingDate);
- boolean postReversals = false;
super.postInterest(mc, interestPostingUpToDate, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestAson,
backdatedTxnsAllowedTill, postReversals);
}
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 90fbb967f..79cba8ee1 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
@@ -977,7 +977,6 @@ public class SavingsAccount extends
AbstractPersistableCustom {
protected void recalculateDailyBalances(final Money openingAccountBalance,
final LocalDate interestPostingUpToDate,
final boolean backdatedTxnsAllowedTill, boolean postReversals) {
-
Money runningBalance = openingAccountBalance.copy();
List<SavingsAccountTransaction> accountTransactionsSorted = null;
@@ -2775,6 +2774,7 @@ public class SavingsAccount extends
AbstractPersistableCustom {
private void payActivationCharges(final boolean
isSavingsInterestPostingAtCurrentPeriodEnd, final Integer
financialYearBeginningMonth,
final AppUser user, final boolean backdatedTxnsAllowedTill) {
boolean isSavingsChargeApplied = false;
+ boolean postReversals = false;
UUID refNo = UUID.randomUUID();
for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
if (savingsAccountCharge.isSavingsActivation()) {
@@ -2788,7 +2788,6 @@ public class SavingsAccount extends
AbstractPersistableCustom {
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
LocalDate postInterestAsOnDate = null;
- boolean postReversals = false;
if (this.isBeforeLastPostingPeriod(getActivationLocalDate(),
backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
this.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
@@ -3551,12 +3550,12 @@ public class SavingsAccount extends
AbstractPersistableCustom {
this.closedOnDate = DateUtils.getBusinessLocalDate();
this.closedBy = appUser;
boolean postInterestAsOnDate = false;
+ boolean postReversals = false;
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
if
(this.getSummary().getAccountBalance(this.getCurrency()).isGreaterThanZero()) {
SavingsAccountTransaction transaction =
SavingsAccountTransaction.escheat(this, transactionDate, appUser,
postInterestAsOnDate);
this.transactions.add(transaction);
}
- boolean postReversals = false;
recalculateDailyBalances(Money.zero(this.currency), transactionDate,
false, postReversals);
this.summary.updateSummary(this.currency,
this.savingsAccountTransactionSummaryWrapper, this.transactions);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
index 555585145..45436ce42 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
@@ -92,6 +92,7 @@ public class SavingsAccountDomainServiceJpa implements
SavingsAccountDomainServi
final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Long relaxingDaysConfigForPivotDate =
this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate();
+ final boolean postReversals =
this.configurationDomainService.isReversalTransactionAllowed();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
if (transactionBooleanValues.isRegularTransaction() &&
!account.allowWithdrawal()) {
throw new
DepositAccountTransactionNotAllowedException(account.getId(), "withdraw",
account.depositAccountType());
@@ -115,7 +116,7 @@ public class SavingsAccountDomainServiceJpa implements
SavingsAccountDomainServi
final MathContext mc = MathContext.DECIMAL64;
final LocalDate today = DateUtils.getBusinessLocalDate();
- boolean postReversals = false;
+
if (account.isBeforeLastPostingPeriod(transactionDate,
backdatedTxnsAllowedTill)) {
account.postInterest(mc, today,
transactionBooleanValues.isInterestTransfer(),
isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate,
backdatedTxnsAllowedTill, postReversals);
@@ -202,7 +203,7 @@ public class SavingsAccountDomainServiceJpa implements
SavingsAccountDomainServi
final MathContext mc = MathContext.DECIMAL64;
final LocalDate today = DateUtils.getBusinessLocalDate();
- boolean postReversals = false;
+ boolean postReversals =
this.configurationDomainService.isReversalTransactionAllowed();
if (account.isBeforeLastPostingPeriod(transactionDate,
backdatedTxnsAllowedTill)) {
account.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, backdatedTxnsAllowedTill,
postReversals);
@@ -297,6 +298,7 @@ public class SavingsAccountDomainServiceJpa implements
SavingsAccountDomainServi
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
final Long relaxingDaysConfigForPivotDate =
this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate();
+ final boolean postReversals = true;
final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>();
@@ -314,7 +316,9 @@ public class SavingsAccountDomainServiceJpa implements
SavingsAccountDomainServi
chargePaidBySet =
savingsAccountTransaction.getSavingsAccountChargesPaid();
reversal.getSavingsAccountChargesPaid().addAll(chargePaidBySet);
account.undoTransaction(savingsAccountTransaction);
- newTransactions.add(reversal);
+ if (postReversals) {
+ newTransactions.add(reversal);
+ }
}
boolean isInterestTransfer = false;
@@ -322,7 +326,6 @@ public class SavingsAccountDomainServiceJpa implements
SavingsAccountDomainServi
final LocalDate today = DateUtils.getBusinessLocalDate();
final MathContext mc = new MathContext(15,
MoneyHelper.getRoundingMode());
for (SavingsAccountTransaction savingsAccountTransaction :
savingsAccountTransactions) {
- boolean postReversals = true;
if (savingsAccountTransaction.isPostInterestCalculationRequired()
&&
account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(),
backdatedTxnsAllowedTill)) {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
index 3aab8ef0a..1a4bceaf3 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -201,7 +201,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
-
+ final boolean postReversals = false;
this.depositAccountTransactionDataValidator.validateActivation(command);
final MathContext mc = MathContext.DECIMAL64;
final FixedDepositAccount account = (FixedDepositAccount)
this.depositAccountAssembler.assembleFrom(savingsId,
@@ -239,7 +239,6 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
}
final boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null;
- final boolean postReversals = false;
if (activationChargeAmount.isGreaterThanZero()) {
payActivationCharge(account, user);
}
@@ -309,7 +308,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
-
+ final boolean postReversals = false;
this.depositAccountTransactionDataValidator.validateActivation(command);
final RecurringDepositAccount account = (RecurringDepositAccount)
this.depositAccountAssembler.assembleFrom(savingsId,
@@ -367,11 +366,10 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
account.updateOverduePayments(overdueUptoDate);
final boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null;
- boolean postReversals = false;
if
(account.isBeforeLastPostingPeriod(account.getActivationLocalDate(), false)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
- postInterestOnDate, false);
+ postInterestOnDate, false, postReversals);
} else {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.calculateInterestUsing(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd,
@@ -523,7 +521,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
checkClientOrGroupActive(account);
final LocalDate today = DateUtils.getBusinessLocalDate();
- boolean postReversals = false;
+ final boolean postReversals = false;
final MathContext mc = new MathContext(15,
MoneyHelper.getRoundingMode());
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
@@ -571,7 +569,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final MathContext mc = new MathContext(10,
MoneyHelper.getRoundingMode());
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
- boolean postReversals = false;
+ final boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals);
this.savingAccountRepositoryWrapper.saveAndFlush(account);
@@ -646,11 +644,11 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
checkClientOrGroupActive(account);
- boolean postReversals = false;
+ final boolean postReversals = false;
if (savingsAccountTransaction.isPostInterestCalculationRequired()
&&
account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(),
false)) {
account.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
- postInterestOnDate, false);
+ postInterestOnDate, false, postReversals);
} else {
account.calculateInterestUsing(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false,
postReversals);
@@ -759,11 +757,11 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Long newtransactionId =
saveTransactionToGenerateTransactionId(transaction);
boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null;
- boolean postReversals = false;
+ final boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, false)
||
account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(),
false)) {
account.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
- postInterestOnDate, false);
+ postInterestOnDate, false, postReversals);
} else {
account.calculateInterestUsing(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false,
postReversals);
@@ -988,7 +986,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
- boolean postReversals = false;
+ final boolean postReversals = false;
savingsAccount.calculateInterestUsing(mc, transferDate,
isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false,
postReversals);
@@ -1020,7 +1018,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.office(), transferDate, user);
savingsAccount.addTransaction(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
- boolean postReversals = false;
+ final boolean postReversals = false;
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
@@ -1066,7 +1064,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.reassignSavingsOfficer(fieldOfficer, transferDate);
}
boolean isInterestTransfer = false;
- boolean postReversals = false;
+ final boolean postReversals = false;
LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate,
isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
@@ -1223,7 +1221,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64;
- boolean postReversals = false;
+ final boolean postReversals = false;
if
(account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(),
false)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
@@ -1363,7 +1361,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64;
- boolean postReversals = false;
+ final boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, false)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
@@ -1394,7 +1392,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final boolean isSavingsInterestPostingAtCurrentPeriodEnd =
this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth =
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
-
+ final boolean postReversals = false;
final SavingsAccount account =
this.depositAccountAssembler.assembleFrom(depositAccountId, depositAccountType);
final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>();
@@ -1429,7 +1427,7 @@ public class
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
}
} else if (depositAccountType.isRecurringDeposit()) {
((RecurringDepositAccount)
account).updateMaturityStatus(isSavingsInterestPostingAtCurrentPeriodEnd,
- financialYearBeginningMonth);
+ financialYearBeginningMonth, postReversals);
}
this.savingAccountRepositoryWrapper.saveAndFlush(account);
postJournalEntries(account, existingTransactionIds,
existingReversedTransactionIds);
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index 25e775ef4..f8cb165ca 100644
---
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -40,4 +40,5 @@
<include file="parts/0018_pentaho_reports_to_table.xml"
relativeToChangelogFile="true"/>
<include file="parts/0019_refactor_loan_transaction.xml"
relativeToChangelogFile="true"/>
<include file="parts/0020_add_audit_entries.xml"
relativeToChangelogFile="true"/>
+ <include file="parts/0026_reversals_for_reversed_transactions.xml"
relativeToChangelogFile="true"/>
</databaseChangeLog>
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0026_reversals_for_reversed_transactions.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0026_reversals_for_reversed_transactions.xml
new file mode 100644
index 000000000..1fdbf358d
--- /dev/null
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0026_reversals_for_reversed_transactions.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+ <changeSet author="fineract" id="1">
+ <insert tableName="c_configuration">
+ <column name="id" valueNumeric="46"/>
+ <column name="name"
value="enable-post-reversal-txns-for-reverse-transactions"/>
+ <column name="value"/>
+ <column name="date_value"/>
+ <column name="string_value"/>
+ <column name="enabled" valueBoolean="false"/>
+ <column name="is_trap_door" valueBoolean="false"/>
+ <column name="description"/>
+ </insert>
+ </changeSet>
+</databaseChangeLog>
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
index d12abc8a3..a98a796a2 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
@@ -2989,6 +2989,70 @@ public class ClientSavingsIntegrationTest {
assertEquals("error.msg.savings.transaction.is.not.allowed",
error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
}
+ @Test
+ public void
testReversalEntriesAfterSystemReversingTransactionWithReversalConfigOn() {
+ this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec,
this.responseSpec);
+ this.savingsProductHelper = new SavingsProductHelper();
+ this.scheduleJobHelper = new SchedulerJobHelper(requestSpec);
+
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
this.responseSpec, "46", true);
+ LocalDate transactionDate =
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5);
+ LocalDate nextTransactionDate = transactionDate.plusDays(2);
+ final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd
MMMM yyyy");
+ String startDate = formatter.format(transactionDate);
+ String nxtTransaction = formatter.format(nextTransactionDate);
+ final String jobName = "Post Interest For Savings";
+ final Integer clientID = ClientHelper.createClient(this.requestSpec,
this.responseSpec, startDate);
+ Assertions.assertNotNull(clientID);
+
+ final Integer savingsId =
createSavingsAccountDailyPostingOverdraft(clientID, startDate);
+ this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId,
"100", startDate, CommonConstants.RESPONSE_RESOURCE_ID);
+ this.scheduleJobHelper.executeAndAwaitJob(jobName);
+ this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId,
"100", nxtTransaction, CommonConstants.RESPONSE_RESOURCE_ID);
+
+ List<HashMap> transactions =
this.savingsAccountHelper.getSavingsTransactions(savingsId);
+ boolean reversalFlag = false;
+ for (int i = 0; i < transactions.size(); i++) {
+ boolean isReversal = (boolean)
transactions.get(i).get("isReversal");
+ if (isReversal) {
+ reversalFlag = true;
+ break;
+ }
+ }
+ Assertions.assertTrue(reversalFlag);
+ }
+
+ @Test
+ public void
testReversalEntriesAfterSystemReversingTransactionWithReversalConfigOff() {
+ this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec,
this.responseSpec);
+ this.savingsProductHelper = new SavingsProductHelper();
+ this.scheduleJobHelper = new SchedulerJobHelper(requestSpec);
+
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
this.responseSpec, "46", false);
+ LocalDate transactionDate =
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5);
+ LocalDate nextTransactionDate = transactionDate.plusDays(2);
+ final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd
MMMM yyyy");
+ String startDate = formatter.format(transactionDate);
+ String nxtTransaction = formatter.format(nextTransactionDate);
+ final String jobName = "Post Interest For Savings";
+ final Integer clientID = ClientHelper.createClient(this.requestSpec,
this.responseSpec, startDate);
+ Assertions.assertNotNull(clientID);
+
+ final Integer savingsId =
createSavingsAccountDailyPostingOverdraft(clientID, startDate);
+ this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId,
"100", startDate, CommonConstants.RESPONSE_RESOURCE_ID);
+ this.scheduleJobHelper.executeAndAwaitJob(jobName);
+ this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId,
"100", nxtTransaction, CommonConstants.RESPONSE_RESOURCE_ID);
+
+ List<HashMap> transactions =
this.savingsAccountHelper.getSavingsTransactions(savingsId);
+ boolean reversalFlag = false;
+ for (int i = 0; i < transactions.size(); i++) {
+ boolean isReversal = (boolean)
transactions.get(i).get("isReversal");
+ if (isReversal) {
+ reversalFlag = true;
+ break;
+ }
+ }
+ Assertions.assertFalse(reversalFlag);
+ }
+
private Integer createSavingsAccountDailyPostingOverdraft(final Integer
clientID, final String startDate) {
final Integer savingsProductID =
createSavingsProductDailyPostingOverdraft();
Assertions.assertNotNull(savingsProductID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
index 12c3e4cc3..231168ce9 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
@@ -99,8 +99,8 @@ public class GlobalConfigurationHelper {
ArrayList<HashMap> actualGlobalConfigurations =
getAllGlobalConfigurations(requestSpec, responseSpec);
// There are currently 37 global configurations.
- Assertions.assertEquals(40, expectedGlobalConfigurations.size());
- Assertions.assertEquals(40, actualGlobalConfigurations.size());
+ Assertions.assertEquals(41, expectedGlobalConfigurations.size());
+ Assertions.assertEquals(41, actualGlobalConfigurations.size());
for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
@@ -456,6 +456,14 @@ public class GlobalConfigurationHelper {
isAutomaticCOBDateAdjustmentEnabled.put("trapDoor", false);
defaults.add(isAutomaticCOBDateAdjustmentEnabled);
+ HashMap<String, Object> isReversalTransactionAllowed = new HashMap<>();
+ isReversalTransactionAllowed.put("id", 46);
+ isReversalTransactionAllowed.put("name",
"enable-post-reversal-txns-for-reverse-transactions");
+ isReversalTransactionAllowed.put("value", 0);
+ isReversalTransactionAllowed.put("enabled", false);
+ isReversalTransactionAllowed.put("trapDoor", false);
+ defaults.add(isReversalTransactionAllowed);
+
return defaults;
}