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;
     }
 

Reply via email to