fineract-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nazeer1100...@apache.org
Subject [1/2] incubator-fineract git commit: Dormant Savings Feature
Date Wed, 04 May 2016 07:30:39 GMT
Repository: incubator-fineract
Updated Branches:
  refs/heads/develop a2d794a34 -> 9d4d90121


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
----------------------------------------------------------------------
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 5cc2065..760ac7c 100755
--- 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
@@ -114,6 +114,7 @@ import org.joda.time.LocalDate;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 import org.springframework.data.jpa.domain.AbstractPersistable;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
 import com.google.gson.JsonArray;
@@ -154,6 +155,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
     @Column(name = "status_enum", nullable = false)
     protected Integer status;
 
+    @Column(name = "sub_status_enum", nullable = false)
+    protected Integer sub_status = 0;
+
     @Column(name = "account_type_enum", nullable = false)
     protected Integer accountType;
 
@@ -901,6 +905,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
         this.transactions.add(transaction);
 
         this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
+        
+        if(this.sub_status.equals(SavingsAccountSubStatusEnum.INACTIVE.getValue())
+        		|| this.sub_status.equals(SavingsAccountSubStatusEnum.DORMANT.getValue())){
+        	this.sub_status = SavingsAccountSubStatusEnum.NONE.getValue();
+        }
 
         return transaction;
     }
@@ -987,6 +996,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
             // auto pay withdrawal fee
             payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate(), transactionDTO.getAppUser());
         }
+        if(this.sub_status.equals(SavingsAccountSubStatusEnum.INACTIVE.getValue())
+        		|| this.sub_status.equals(SavingsAccountSubStatusEnum.DORMANT.getValue())){
+        	this.sub_status = SavingsAccountSubStatusEnum.NONE.getValue();
+        }
         return transaction;
     }
 
@@ -2744,4 +2757,37 @@ public class SavingsAccount extends AbstractPersistable<Long> {
 
         return recalucateDailyBalance;
     }
+
+	public void setSubStatusInactive(AppUser appUser) {
+		this.sub_status = SavingsAccountSubStatusEnum.INACTIVE.getValue();
+    	LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
+        for (SavingsAccountCharge charge : this.charges()) {
+            if (charge.isSavingsNoActivity() && charge.isActive()) {
+                charge.updateWithdralFeeAmount(this.getAccountBalance());
+                this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, appUser);
+            }
+        }
+        recalculateDailyBalances(Money.zero(this.currency), transactionDate);
+        this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
+	}
+	
+
+	public void setSubStatusDormant() {
+		this.sub_status = SavingsAccountSubStatusEnum.DORMANT.getValue();
+	}
+
+	public void escheat(AppUser appUser) {
+		this.status = SavingsAccountStatusType.CLOSED.getValue();
+		this.sub_status = SavingsAccountSubStatusEnum.ESCHEAT.getValue();
+		this.closedOnDate = DateUtils.getDateOfTenant();
+		this.closedBy = appUser;
+		
+    	LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
+		if(this.getSummary().getAccountBalance(this.getCurrency()).isGreaterThanZero()){
+			SavingsAccountTransaction transaction = SavingsAccountTransaction.escheat(this, transactionDate, appUser);
+			this.transactions.add(transaction);
+		}
+        recalculateDailyBalances(Money.zero(this.currency), transactionDate);
+		this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
+	}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountCharge.java
----------------------------------------------------------------------
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 395797c..fe40f3b 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
@@ -656,6 +656,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
     public boolean isSavingsActivation() {
         return ChargeTimeType.fromInt(this.chargeTime).isSavingsActivation();
     }
+    
+    public boolean isSavingsNoActivity(){
+    	return ChargeTimeType.fromInt(this.chargeTime).isSavingsNoActivityFee();
+    }
 
     public boolean isSavingsClosure() {
         return ChargeTimeType.fromInt(this.chargeTime).isSavingsClosure();

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
new file mode 100644
index 0000000..aefe183
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
@@ -0,0 +1,85 @@
+/**
+ * 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.
+ */
+package org.apache.fineract.portfolio.savings.domain;
+
+/**
+ * Enum representation of {@link SavingsAccount} sub-status states.
+ */
+public enum SavingsAccountSubStatusEnum {
+
+    NONE(0, "SavingsAccountSubStatusEnum.none"), //
+    INACTIVE(100, "SavingsAccountSubStatusEnum.inactive"), //
+    DORMANT(200, "SavingsAccountSubStatusEnum.dormant"),
+    ESCHEAT(300,"SavingsAccountSubStatusEnum.escheat");
+
+    private final Integer value;
+    private final String code;
+
+    public static SavingsAccountSubStatusEnum fromInt(final Integer type) {
+
+    	SavingsAccountSubStatusEnum enumeration = SavingsAccountSubStatusEnum.NONE;
+    	if(null != type){
+            switch (type) {
+	            case 100:
+	                enumeration = SavingsAccountSubStatusEnum.INACTIVE;
+	            break;
+	            case 200:
+	                enumeration = SavingsAccountSubStatusEnum.DORMANT;
+	            break;
+	            case 300:
+	                enumeration = SavingsAccountSubStatusEnum.ESCHEAT;
+	            break;
+	        }
+    	}
+        return enumeration;
+    }
+
+    private SavingsAccountSubStatusEnum(final Integer value, final String code) {
+        this.value = value;
+        this.code = code;
+    }
+
+    public boolean hasStateOf(final SavingsAccountSubStatusEnum state) {
+        return this.value.equals(state.getValue());
+    }
+
+    public Integer getValue() {
+        return this.value;
+    }
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public boolean isSubStatusInactive() {
+        return this.value.equals(SavingsAccountSubStatusEnum.INACTIVE.getValue());
+    }
+
+    public boolean isSubStatusDormant() {
+        return this.value.equals(SavingsAccountSubStatusEnum.DORMANT.getValue());
+    }
+
+    public boolean isSubStatusNone() {
+        return this.value.equals(SavingsAccountSubStatusEnum.NONE.getValue());
+    }
+
+    public boolean isSubStatusEscheat() {
+        return this.value.equals(SavingsAccountSubStatusEnum.ESCHEAT.getValue());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
index 2e6abcc..8c4fc27 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
@@ -228,6 +228,15 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
         return accountTransaction;
     }
 
+    public static SavingsAccountTransaction escheat(final SavingsAccount savingsAccount, final LocalDate date,
+            final AppUser appUser) {
+        final boolean isReversed = false;
+        final PaymentDetail paymentDetail = null;
+        return new SavingsAccountTransaction(savingsAccount, savingsAccount.office(), paymentDetail,
+                SavingsAccountTransactionType.ESCHEAT.getValue(), date, new Date(), savingsAccount.getSummary()
+                        .getAccountBalance(), isReversed, appUser);
+    }
+
     public static void updateTaxDetails(final Map<TaxComponent, BigDecimal> taxDetails, final SavingsAccountTransaction accountTransaction) {
         if (taxDetails != null) {
             for (Map.Entry<TaxComponent, BigDecimal> mapEntry : taxDetails.entrySet()) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java
index 1b100a0..4415c71 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java
@@ -46,6 +46,10 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNam
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.isDormancyTrackingActiveParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToInactiveParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToDormancyParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToEscheatParamName;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
@@ -191,6 +195,18 @@ public class SavingsProduct extends AbstractPersistable<Long> {
     @JoinColumn(name = "tax_group_id")
     private TaxGroup taxGroup;
 
+	@Column(name = "is_dormancy_tracking_active")
+	private Boolean isDormancyTrackingActive;
+
+    @Column(name = "days_to_inactive")
+	private Long daysToInactive;
+
+    @Column(name = "days_to_dormancy")
+	private Long daysToDormancy;
+
+    @Column(name = "days_to_escheat")
+	private Long daysToEscheat;
+
     public static SavingsProduct createNew(final String name, final String shortName, final String description,
             final MonetaryCurrency currency, final BigDecimal interestRate,
             final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
@@ -201,13 +217,15 @@ public class SavingsProduct extends AbstractPersistable<Long> {
             final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
             final BigDecimal minRequiredBalance, final BigDecimal minBalanceForInterestCalculation,
             final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation,
-            boolean withHoldTax, TaxGroup taxGroup) {
+            boolean withHoldTax, TaxGroup taxGroup, 
+            final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy, final Long daysToEscheat) {
 
         return new SavingsProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
                 interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
                 lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges,
                 allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation,
-                nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup);
+                nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup,
+                isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
     }
 
     protected SavingsProduct() {
@@ -226,7 +244,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
         this(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
                 interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
                 lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, allowOverdraft, overdraftLimit,
-                false, null, minBalanceForInterestCalculation, null, null, withHoldTax, taxGroup);
+                false, null, minBalanceForInterestCalculation, null, null, withHoldTax, taxGroup, null, null, null, null);
     }
 
     protected SavingsProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
@@ -238,7 +256,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
             final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
             final BigDecimal minRequiredBalance, BigDecimal minBalanceForInterestCalculation,
             final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation,
-            final boolean withHoldTax, final TaxGroup taxGroup) {
+            final boolean withHoldTax, final TaxGroup taxGroup,
+            final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy, final Long daysToEscheat) {
 
         this.name = name;
         this.shortName = shortName;
@@ -283,6 +302,11 @@ public class SavingsProduct extends AbstractPersistable<Long> {
         this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
         this.withHoldTax = withHoldTax;
         this.taxGroup = taxGroup;
+        
+        this.isDormancyTrackingActive = isDormancyTrackingActive;
+        this.daysToInactive = daysToInactive;
+        this.daysToDormancy = daysToDormancy;
+        this.daysToEscheat = daysToEscheat;
     }
 
     /**
@@ -541,6 +565,36 @@ public class SavingsProduct extends AbstractPersistable<Long> {
         } else {
             this.taxGroup = null;
         }
+        
+        if(command.isChangeInBooleanParameterNamed(isDormancyTrackingActiveParamName, this.isDormancyTrackingActive)){
+            final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isDormancyTrackingActiveParamName);
+            actualChanges.put(isDormancyTrackingActiveParamName, newValue);
+            this.isDormancyTrackingActive = newValue;
+        }
+
+        if(command.isChangeInLongParameterNamed(daysToInactiveParamName, this.daysToInactive)){
+            final Long newValue = command.longValueOfParameterNamed(daysToInactiveParamName);
+            actualChanges.put(daysToInactiveParamName, newValue);
+            this.daysToInactive = newValue;
+        }
+
+        if(command.isChangeInLongParameterNamed(daysToDormancyParamName, this.daysToDormancy)){
+            final Long newValue = command.longValueOfParameterNamed(daysToDormancyParamName);
+            actualChanges.put(daysToDormancyParamName, newValue);
+            this.daysToDormancy = newValue;
+        }
+
+        if(command.isChangeInLongParameterNamed(daysToEscheatParamName, this.daysToEscheat)){
+            final Long newValue = command.longValueOfParameterNamed(daysToEscheatParamName);
+            actualChanges.put(daysToEscheatParamName, newValue);
+            this.daysToEscheat = newValue;
+        }
+        
+        if(!this.isDormancyTrackingActive){
+        	this.daysToInactive = null;
+        	this.daysToDormancy = null;
+        	this.daysToEscheat = null;
+        }
 
         validateLockinDetails();
         esnureOverdraftLimitsSetForOverdraftAccounts();
@@ -676,4 +730,20 @@ public class SavingsProduct extends AbstractPersistable<Long> {
         return this.withHoldTax;
     }
 
+    public boolean isDormancyTrackingActive() {
+		return null == this.isDormancyTrackingActive? false: this.isDormancyTrackingActive;
+	}
+
+	public Long getDaysToInactive() {
+		return this.daysToInactive;
+	}
+
+	public Long getDaysToDormancy() {
+		return this.daysToDormancy;
+	}
+
+	public Long getDaysToEscheat() {
+		return this.daysToEscheat;
+	}
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java
index dcbfe93..e52e6dc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java
@@ -44,6 +44,10 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraf
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.isDormancyTrackingActiveParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToInactiveParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToDormancyParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToEscheatParamName;
 
 import java.math.BigDecimal;
 import java.util.HashSet;
@@ -173,12 +177,18 @@ public class SavingsProductAssembler {
 
         boolean withHoldTax = command.booleanPrimitiveValueOfParameterNamed(withHoldTaxParamName);
         final TaxGroup taxGroup = assembleTaxGroup(command);
+        
+        final Boolean isDormancyTrackingActive = command.booleanObjectValueOfParameterNamed(isDormancyTrackingActiveParamName);
+        final Long daysToInactive = command.longValueOfParameterNamed(daysToInactiveParamName);
+        final Long daysToDormancy = command.longValueOfParameterNamed(daysToDormancyParamName);
+        final Long daysToEscheat = command.longValueOfParameterNamed(daysToEscheatParamName);
 
         return SavingsProduct.createNew(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
                 interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
                 lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, accountingRuleType, charges,
                 allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation,
-                nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup);
+                nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup,
+                isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
     }
 
     public Set<Charge> assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java
index b9835f1..0637c46 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java
@@ -19,12 +19,14 @@
 package org.apache.fineract.portfolio.savings.service;
 
 import java.util.Collection;
+import java.util.List;
 
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
+import org.joda.time.LocalDate;
 
 public interface SavingsAccountReadPlatformService {
 
@@ -50,4 +52,10 @@ public interface SavingsAccountReadPlatformService {
     SavingsAccountTransactionData retrieveSavingsTransaction(Long savingsId, Long transactionId, DepositAccountType depositAccountType);
 
     Collection<SavingsAccountData> retrieveForLookup(Long clientId, Boolean overdraft);
+    
+    List<Long> retrieveSavingsIdsPendingInactive(LocalDate tenantLocalDate);
+
+    List<Long> retrieveSavingsIdsPendingDormant(LocalDate tenantLocalDate);
+
+    List<Long> retrieveSavingsIdsPendingEscheat(LocalDate tenantLocalDate);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
index 022f61e..8d93f46 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
@@ -24,6 +24,8 @@ import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Date;
+import java.util.List;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
@@ -38,6 +40,7 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.staff.data.StaffData;
 import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
 import org.apache.fineract.portfolio.account.data.AccountTransferData;
+import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 import org.apache.fineract.portfolio.charge.data.ChargeData;
 import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
 import org.apache.fineract.portfolio.client.data.ClientData;
@@ -56,15 +59,22 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountApplicationTimel
 import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountStatusEnumData;
+import org.apache.fineract.portfolio.savings.data.SavingsAccountSubStatusEnumData;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountSummaryData;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
 import org.apache.fineract.portfolio.savings.data.SavingsProductData;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountSubStatusEnum;
 import org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException;
 import org.apache.fineract.portfolio.tax.data.TaxGroupData;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.joda.time.Days;
 import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.core.RowMapper;
@@ -82,6 +92,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
     private final StaffReadPlatformService staffReadPlatformService;
     private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
     private final ChargeReadPlatformService chargeReadPlatformService;
+	private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
 
     // mappers
     private final SavingsAccountTransactionTemplateMapper transactionTemplateMapper;
@@ -217,7 +228,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
             sqlBuilder.append("sp.id as productId, sp.name as productName, ");
             sqlBuilder.append("s.id fieldOfficerId, s.display_name as fieldOfficerName, ");
             sqlBuilder.append("sa.status_enum as statusEnum, ");
-
+            sqlBuilder.append("sa.sub_status_enum as subStatusEnum, ");
             sqlBuilder.append("sa.submittedon_date as submittedOnDate,");
             sqlBuilder.append("sbu.username as submittedByUsername,");
             sqlBuilder.append("sbu.firstname as submittedByFirstname, sbu.lastname as submittedByLastname,");
@@ -282,8 +293,16 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
             sqlBuilder.append("sa.on_hold_funds_derived as onHoldFunds, ");
             sqlBuilder.append("sa.withhold_tax as withHoldTax,");
             sqlBuilder.append("sa.total_withhold_tax_derived as totalWithholdTax,");
-            sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName ");
-
+            sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, ");
+            sqlBuilder.append("(select IFNULL(max(sat.transaction_date),sa.activatedon_date) ");
+            sqlBuilder.append("from m_savings_account_transaction as sat ");
+            sqlBuilder.append("where sat.is_reversed = 0 ");
+            sqlBuilder.append("and sat.transaction_type_enum in (1,2) ");
+            sqlBuilder.append("and sat.savings_account_id = sa.id) as lastActiveTransactionDate, ");
+            sqlBuilder.append("sp.is_dormancy_tracking_active as isDormancyTrackingActive, ");
+            sqlBuilder.append("sp.days_to_inactive as daysToInactive, ");
+            sqlBuilder.append("sp.days_to_dormancy as daysToDormancy, ");
+            sqlBuilder.append("sp.days_to_escheat as daysToEscheat ");
             sqlBuilder.append("from m_savings_account sa ");
             sqlBuilder.append("join m_savings_product sp ON sa.product_id = sp.id ");
             sqlBuilder.append("join m_currency curr on curr.code = sa.currency_code ");
@@ -328,6 +347,31 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
             final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
             final SavingsAccountStatusEnumData status = SavingsEnumerations.status(statusEnum);
 
+            final Integer subStatusEnum = JdbcSupport.getInteger(rs, "subStatusEnum");
+            final SavingsAccountSubStatusEnumData subStatus = SavingsEnumerations.subStatus(subStatusEnum);
+            
+            final LocalDate lastActiveTransactionDate = JdbcSupport.getLocalDate(rs, "lastActiveTransactionDate");
+            final boolean isDormancyTrackingActive = rs.getBoolean("isDormancyTrackingActive");
+            final Integer numDaysToInactive = JdbcSupport.getInteger(rs, "daysToInactive");
+            final Integer numDaysToDormancy = JdbcSupport.getInteger(rs, "daysToDormancy");
+            final Integer numDaysToEscheat = JdbcSupport.getInteger(rs, "daysToEscheat");
+            Integer daysToInactive = null;
+            Integer daysToDormancy = null;
+            Integer daysToEscheat = null;
+
+        	LocalDate localTenantDate = DateUtils.getLocalDateOfTenant();
+            if(isDormancyTrackingActive && statusEnum.equals(SavingsAccountStatusType.ACTIVE.getValue())){
+            	if(subStatusEnum < SavingsAccountSubStatusEnum.ESCHEAT.getValue()){
+                    daysToEscheat = Days.daysBetween(localTenantDate,lastActiveTransactionDate.plusDays(numDaysToEscheat)).getDays();
+            	}
+            	if(subStatusEnum < SavingsAccountSubStatusEnum.DORMANT.getValue()){
+                    daysToDormancy = Days.daysBetween(localTenantDate,lastActiveTransactionDate.plusDays(numDaysToDormancy)).getDays();
+            	}
+            	if(subStatusEnum < SavingsAccountSubStatusEnum.INACTIVE.getValue()){
+                    daysToInactive = Days.daysBetween(localTenantDate,lastActiveTransactionDate.plusDays(numDaysToInactive)).getDays(); 
+            	}
+            }
+
             final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
             final String submittedByUsername = rs.getString("submittedByUsername");
             final String submittedByFirstname = rs.getString("submittedByFirstname");
@@ -469,11 +513,12 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
             }
 
             return SavingsAccountData.instance(id, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId,
-                    productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate,
-                    interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
-                    minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
-                    allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation,
-                    onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroupData);
+                    productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency,
+                    nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
+                    interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers,
+                    summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
+                    minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, 
+                    taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
         }
     }
 
@@ -996,15 +1041,23 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
             // final LocalDate annualFeeNextDueDate = null;
             final SavingsAccountSummaryData summary = null;
             final BigDecimal onHoldFunds = null;
+            
+            final SavingsAccountSubStatusEnumData subStatus = null;
+            final LocalDate lastActiveTransactionDate = null;
+            final boolean isDormancyTrackingActive = false;
+            final Integer daysToInactive = null;
+            final Integer daysToDormancy = null;
+            final Integer daysToEscheat = null;
 
             final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault();
             final EnumOptionData depositType = null;
             return SavingsAccountData.instance(null, null, depositType, null, groupId, groupName, clientId, clientName, productId,
-                    productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualIterestRate,
-                    interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
-                    minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
-                    allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation,
-                    onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroupData);
+                    productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency,
+                    nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
+                    interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers,
+                    summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
+                    minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, 
+                    taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
         }
     }
 
@@ -1025,6 +1078,84 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
 
     }
 
+	@Override
+	public List<Long> retrieveSavingsIdsPendingInactive(
+			LocalDate tenantLocalDate) {
+		List<Long> ret = null;
+		StringBuilder sql = new StringBuilder("select sa.id ");
+		sql.append(" from m_savings_account as sa ");
+		sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = 1) ");
+		sql.append(" where sa.status_enum = 300 ");
+		sql.append(" and sa.sub_status_enum = 0 ");
+		sql.append(" and DATEDIFF(?,(select IFNULL(max(sat.transaction_date),sa.activatedon_date) ");
+		sql.append(" from m_savings_account_transaction as sat ");
+		sql.append(" where sat.is_reversed = 0 ");
+		sql.append(" and sat.transaction_type_enum in (1,2) ");
+		sql.append(" and sat.savings_account_id = sa.id)) >= sp.days_to_inactive "); 
+		
+		try {
+			ret =  this.jdbcTemplate.queryForList(sql.toString(), Long.class, new Object[] {formatter.print(tenantLocalDate)});
+		} catch (EmptyResultDataAccessException e) {
+			// ignore empty result scenario
+		} catch (DataAccessException e) {
+			throw e;
+		}
+		
+		return ret;
+	}
+
+	@Override
+	public List<Long> retrieveSavingsIdsPendingDormant(
+			LocalDate tenantLocalDate) {
+		List<Long> ret = null;
+		StringBuilder sql = new StringBuilder("select sa.id ");
+		sql.append(" from m_savings_account as sa ");
+		sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = 1) ");
+		sql.append(" where sa.status_enum = 300 ");
+		sql.append(" and sa.sub_status_enum = 100 ");
+		sql.append(" and DATEDIFF(?,(select IFNULL(max(sat.transaction_date),sa.activatedon_date) ");
+		sql.append(" from m_savings_account_transaction as sat ");
+		sql.append(" where sat.is_reversed = 0 ");
+		sql.append(" and sat.transaction_type_enum in (1,2) ");
+		sql.append(" and sat.savings_account_id = sa.id)) >= sp.days_to_dormancy "); 
+		
+		try {
+			ret =  this.jdbcTemplate.queryForList(sql.toString(), Long.class, new Object[] {formatter.print(tenantLocalDate)});
+		} catch (EmptyResultDataAccessException e) {
+			// ignore empty result scenario
+		} catch (DataAccessException e) {
+			throw e;
+		}
+		
+		return ret;
+	}
+
+	@Override
+	public List<Long> retrieveSavingsIdsPendingEscheat(
+			LocalDate tenantLocalDate) {
+		List<Long> ret = null;
+		StringBuilder sql = new StringBuilder("select sa.id ");
+		sql.append(" from m_savings_account as sa ");
+		sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = 1) ");
+		sql.append(" where sa.status_enum = 300 ");
+		sql.append(" and sa.sub_status_enum = 200 ");
+		sql.append(" and DATEDIFF(?,(select IFNULL(max(sat.transaction_date),sa.activatedon_date) ");
+		sql.append(" from m_savings_account_transaction as sat ");
+		sql.append(" where sat.is_reversed = 0 ");
+		sql.append(" and sat.transaction_type_enum in (1,2) ");
+		sql.append(" and sat.savings_account_id = sa.id)) >= sp.days_to_escheat "); 
+		
+		try {
+			ret =  this.jdbcTemplate.queryForList(sql.toString(), Long.class, new Object[] {formatter.print(tenantLocalDate)});
+		} catch (EmptyResultDataAccessException e) {
+			// ignore empty result scenario
+		} catch (DataAccessException e) {
+			throw e;
+		}
+		
+		return ret;
+	}
+
     /*
      * private static final class SavingsAccountAnnualFeeMapper implements
      * RowMapper<SavingsAccountAnnualFeeData> {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformService.java
index 3fe8aa9..d428d42 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformService.java
@@ -81,4 +81,10 @@ public interface SavingsAccountWritePlatformService {
     void postInterest(SavingsAccount account);
 
     CommandProcessingResult modifyWithHoldTax(Long savingsAccountId, JsonCommand command);
+
+	void setSubStatusInactive(Long savingsId);
+
+	void setSubStatusDormant(Long savingsId);
+
+	void escheat(Long savingsId);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
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 f1b338b..6612c88 100755
--- 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
@@ -78,6 +78,7 @@ import org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentE
 import org.apache.fineract.portfolio.savings.exception.SavingsOfficerUnassignmentException;
 import org.apache.fineract.portfolio.savings.exception.TransactionUpdateNotAllowedException;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
 import org.joda.time.LocalDate;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
@@ -130,6 +131,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
     private final WorkingDaysRepositoryWrapper workingDaysRepository;
     private final ConfigurationDomainService configurationDomainService;
     private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
+    private final AppUserRepositoryWrapper appuserRepository;
 
     @Autowired
     public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -148,7 +150,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
             final ChargeRepositoryWrapper chargeRepository, final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository,
             final SavingsAccountDataValidator fromApiJsonDeserializer, final SavingsAccountRepositoryWrapper savingsRepository,
             final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService,
-            final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository) {
+            final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
+            final AppUserRepositoryWrapper appuserRepository) {
         this.context = context;
         this.savingAccountRepository = savingAccountRepository;
         this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
@@ -171,6 +174,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
         this.staffRepository = staffRepository;
         this.configurationDomainService = configurationDomainService;
         this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository;
+        this.appuserRepository = appuserRepository;
     }
 
     @Transactional
@@ -1223,7 +1227,39 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
                 .build();
     }
 
-    private AppUser getAppUserIfPresent() {
+    @Override
+    @Transactional
+	public void setSubStatusInactive(Long savingsId){
+        final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
+        final Set<Long> existingTransactionIds = new HashSet<>();
+        final Set<Long> existingReversedTransactionIds = new HashSet<>();
+        updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
+        account.setSubStatusInactive(appuserRepository.fetchSystemUser());
+        this.savingAccountRepository.save(account);
+        postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
+    }
+
+    @Override
+    @Transactional
+	public void setSubStatusDormant(Long savingsId){
+        final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
+        account.setSubStatusDormant();
+    	this.savingAccountRepository.save(account);
+    }
+
+    @Override
+    @Transactional
+	public void escheat(Long savingsId){
+        final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
+        final Set<Long> existingTransactionIds = new HashSet<>();
+        final Set<Long> existingReversedTransactionIds = new HashSet<>();
+        updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
+        account.escheat(appuserRepository.fetchSystemUser());
+        this.savingAccountRepository.save(account);
+        postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
+    }
+	
+	private AppUser getAppUserIfPresent() {
         AppUser user = null;
         if (this.context != null) {
             user = this.context.getAuthenticatedUserIfPresent();

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java
index 270562e..9bc4566 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java
@@ -36,8 +36,10 @@ import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
 import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
 import org.apache.fineract.portfolio.savings.SavingsWithdrawalFeesType;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountStatusEnumData;
+import org.apache.fineract.portfolio.savings.data.SavingsAccountSubStatusEnumData;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountSubStatusEnum;
 
 public class SavingsEnumerations {
 
@@ -187,6 +189,10 @@ public class SavingsEnumerations {
                 optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.DIVIDEND_PAYOUT.getValue().longValue(),
                         SavingsAccountTransactionType.DIVIDEND_PAYOUT.getCode(), "Dividend Payout");
                 break;
+            case ESCHEAT:
+                optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.ESCHEAT.getValue().longValue(),
+                        SavingsAccountTransactionType.ESCHEAT.getCode(), "Escheat");
+                break;
         }
         return optionData;
     }
@@ -278,6 +284,39 @@ public class SavingsEnumerations {
         return optionData;
     }
 
+    public static SavingsAccountSubStatusEnumData subStatus(final Integer subStatusEnum) {
+        return subStatus(SavingsAccountSubStatusEnum.fromInt(subStatusEnum));
+    }
+
+    public static SavingsAccountSubStatusEnumData subStatus(final SavingsAccountSubStatusEnum type) {
+
+        final boolean none = type.isSubStatusNone();
+        final boolean inactive = type.isSubStatusInactive();
+        final boolean dormant = type.isSubStatusDormant();
+        final boolean escheat = type.isSubStatusEscheat();
+
+        SavingsAccountSubStatusEnumData optionData = new SavingsAccountSubStatusEnumData(SavingsAccountSubStatusEnum.NONE.getValue().longValue(),
+        		SavingsAccountSubStatusEnum.NONE.getCode(), "None", true, inactive, dormant, escheat);
+
+        switch (type) {
+            case INACTIVE:
+                optionData = new SavingsAccountSubStatusEnumData(SavingsAccountSubStatusEnum.INACTIVE.getValue().longValue(),
+                		SavingsAccountSubStatusEnum.INACTIVE.getCode(), "Inactive", none, inactive, dormant, escheat);
+            break;
+            case DORMANT:
+                optionData = new SavingsAccountSubStatusEnumData(SavingsAccountSubStatusEnum.DORMANT.getValue().longValue(),
+                		SavingsAccountSubStatusEnum.DORMANT.getCode(), "Dormant", none, inactive, dormant, escheat);
+            break;
+            case ESCHEAT:
+                optionData = new SavingsAccountSubStatusEnumData(SavingsAccountSubStatusEnum.ESCHEAT.getValue().longValue(),
+                		SavingsAccountSubStatusEnum.ESCHEAT.getCode(), "Escheat", none, inactive, dormant, escheat);
+            break;
+            default:
+            break;
+        }
+        return optionData;
+    }
+
     public static EnumOptionData interestPostingPeriodType(final Integer type) {
         return interestPostingPeriodType(SavingsPostingInterestPeriodType.fromInt(type));
     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java
index 1fc785e..454cbe3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java
@@ -134,7 +134,11 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
             sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation,");
             sqlBuilder.append("sp.accounting_type as accountingType, ");
             sqlBuilder.append("sp.withhold_tax as withHoldTax,");
-            sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName ");
+            sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, ");
+            sqlBuilder.append("sp.is_dormancy_tracking_active as isDormancyTrackingActive,");
+            sqlBuilder.append("sp.days_to_inactive as daysToInactive,");
+            sqlBuilder.append("sp.days_to_dormancy as daysToDormancy,");
+            sqlBuilder.append("sp.days_to_escheat as daysToEscheat ");
             sqlBuilder.append("from m_savings_product sp ");
             sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
             sqlBuilder.append("left join m_tax_group tg on tg.id = sp.tax_group_id  ");
@@ -210,13 +214,18 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
             if (taxGroupId != null) {
                 taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName);
             }
-
+            
+            final Boolean isDormancyTrackingActive = rs.getBoolean("isDormancyTrackingActive");
+            final Long daysToInactive = JdbcSupport.getLong(rs, "daysToInactive");
+            final Long daysToDormancy = JdbcSupport.getLong(rs, "daysToDormancy");
+            final Long daysToEscheat = JdbcSupport.getLong(rs, "daysToEscheat");
+            
             return SavingsProductData.instance(id, name, shortName, description, currency, nominalAnnualInterestRate,
                     compoundingInterestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
                     minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers,
                     accountingRuleType, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
                     minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax,
-                    taxGroupData);
+                    taxGroupData, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java
index 83cfb8a..c864dc1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java
@@ -145,11 +145,11 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
 
         try {
             this.context.authenticatedUser();
-            this.fromApiJsonDataValidator.validateForUpdate(command.json());
-
             final SavingsProduct product = this.savingProductRepository.findOne(productId);
             if (product == null) { throw new SavingsProductNotFoundException(productId); }
 
+            this.fromApiJsonDataValidator.validateForUpdate(command.json(), product);
+
             final Map<String, Object> changes = product.update(command);
 
             if (changes.containsKey(chargesParamName)) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularService.java
index 13c3471..b2117fa 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularService.java
@@ -24,5 +24,7 @@ import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
 public interface SavingsSchedularService {
 
     void postInterestForAccounts() throws JobExecutionException;
+    
+    void updateSavingsDormancyStatus() throws JobExecutionException;
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
index 6e8e619..24aefa6 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.savings.service;
 
 import java.util.List;
 
+import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
 import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
 import org.apache.fineract.infrastructure.jobs.service.JobName;
@@ -27,6 +28,7 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
+import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -36,14 +38,17 @@ public class SavingsSchedularServiceImpl implements SavingsSchedularService {
     private final SavingsAccountAssembler savingAccountAssembler;
     private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
     private final SavingsAccountRepository savingAccountRepository;
+    private final SavingsAccountReadPlatformService savingAccountReadPlatformService;
 
     @Autowired
     public SavingsSchedularServiceImpl(final SavingsAccountAssembler savingAccountAssembler,
             final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
-            final SavingsAccountRepository savingAccountRepository) {
+            final SavingsAccountRepository savingAccountRepository,
+            final SavingsAccountReadPlatformService savingAccountReadPlatformService) {
         this.savingAccountAssembler = savingAccountAssembler;
         this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
         this.savingAccountRepository = savingAccountRepository;
+        this.savingAccountReadPlatformService = savingAccountReadPlatformService;
     }
 
     @CronTarget(jobName = JobName.POST_INTEREST_FOR_SAVINGS)
@@ -68,4 +73,34 @@ public class SavingsSchedularServiceImpl implements SavingsSchedularService {
         
         if (sb.length() > 0) { throw new JobExecutionException(sb.toString()); }
     }
+
+    @CronTarget(jobName = JobName.UPDATE_SAVINGS_DORMANT_ACCOUNTS)
+    @Override
+    public void updateSavingsDormancyStatus() throws JobExecutionException {
+    	final LocalDate tenantLocalDate = DateUtils.getLocalDateOfTenant();
+
+    	final List<Long> savingsPendingInactive = this.savingAccountReadPlatformService
+    													.retrieveSavingsIdsPendingInactive(tenantLocalDate);
+    	if(null != savingsPendingInactive && savingsPendingInactive.size() > 0){
+    		for(Long savingsId : savingsPendingInactive){
+    			this.savingsAccountWritePlatformService.setSubStatusInactive(savingsId);
+    		}
+    	}
+
+    	final List<Long> savingsPendingDormant = this.savingAccountReadPlatformService
+				.retrieveSavingsIdsPendingDormant(tenantLocalDate);
+		if(null != savingsPendingDormant && savingsPendingDormant.size() > 0){
+			for(Long savingsId : savingsPendingDormant){
+				this.savingsAccountWritePlatformService.setSubStatusDormant(savingsId);
+			}
+		}
+
+    	final List<Long> savingsPendingEscheat = this.savingAccountReadPlatformService
+				.retrieveSavingsIdsPendingEscheat(tenantLocalDate);
+		if(null != savingsPendingEscheat && savingsPendingEscheat.size() > 0){
+			for(Long savingsId : savingsPendingEscheat){
+				this.savingsAccountWritePlatformService.escheat(savingsId);
+			}
+		}
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/9d4d9012/fineract-provider/src/main/resources/sql/migrations/core_db/V303__Savings_Account_Dormancy.sql
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V303__Savings_Account_Dormancy.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V303__Savings_Account_Dormancy.sql
new file mode 100644
index 0000000..6820148
--- /dev/null
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V303__Savings_Account_Dormancy.sql
@@ -0,0 +1,18 @@
+ALTER TABLE `m_savings_product`
+ADD COLUMN `is_dormancy_tracking_active` SMALLINT(1) NULL,
+ADD COLUMN `days_to_inactive` INT(11) NULL,
+ADD COLUMN `days_to_dormancy` INT(11) NULL,
+ADD COLUMN `days_to_escheat` INT(11) NULL;
+
+ALTER TABLE `m_savings_account`
+ADD COLUMN `sub_status_enum` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `status_enum`;
+
+INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`) VALUES ('Update Savings Dormant Accounts', 'Update Savings Dormant Accounts', '0 0 0 1/1 * ? *', now());
+
+INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Savings Accounts Dormancy Report', 'Table', 'Savings', 'select cl.display_name as \'Client Display Name\',\r\nsa.account_no as \'Account Number\',\r\ncl.mobile_no as \'Mobile Number\',\r\n@lastdate:=(select IFNULL(max(sat.transaction_date),sa.activatedon_date) \r\n            from m_savings_account_transaction as sat \r\n            where sat.is_reversed = 0 \r\n            and sat.transaction_type_enum in (1,2) \r\n            and sat.savings_account_id = sa.id) as \'Date of Last Activity\',\r\nDATEDIFF(now(), @lastdate) as \'Days Since Last Activity\'\r\nfrom m_savings_account as sa \r\ninner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = 1) \r\nleft join m_client as cl on sa.client_id = cl.id \r\nwhere sa.sub_status_enum = ${subStatus}\r\nand cl.office_id = ${officeId}', NULL, 1, 1);
+
+INSERT INTO `stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `parameter_sql`) VALUES ('SavingsAccountSubStatus', 'subStatus', 'SavingsAccountDormancyStatus', 'select', 'number', '100', 'select * from\r\n(select 100 as id, "Inactive" as name  union all\r\nselect 200 as id, "Dormant" as  name union all \r\nselect 300 as id, "Escheat" as name) x\r\norder by x.`id`');
+
+INSERT INTO stretchy_report_parameter (report_id, parameter_id) VALUES ((select sr.id From stretchy_report sr where sr.report_name='Savings Accounts Dormancy Report'),(select sp.id from stretchy_parameter sp where sp.parameter_name='SavingsAccountSubStatus'));
+
+INSERT INTO stretchy_report_parameter (report_id, parameter_id) VALUES ((select sr.id From stretchy_report sr where sr.report_name='Savings Accounts Dormancy Report'),(select sp.id from stretchy_parameter sp where sp.parameter_name='OfficeIdSelectOne'));


Mime
View raw message