fineract-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From av...@apache.org
Subject [fineract] branch develop updated: FINERACT-893-fixed-deposit-rollover
Date Tue, 26 May 2020 15:37:53 GMT
This is an automated email from the ASF dual-hosted git repository.

avikg pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new bd99138  FINERACT-893-fixed-deposit-rollover
     new 50d5d08  Merge pull request #769 from fynmanoj/findevfdrollover
bd99138 is described below

commit bd99138aadbb184f0ec563c8111cc79f132ee98d
Author: Manoj <manoj@fynarfin.io>
AuthorDate: Sat May 23 22:52:39 2020 +0530

    FINERACT-893-fixed-deposit-rollover
---
 .../integrationtests/FixedDepositTest.java         | 180 +++++++++++++++++++++
 .../fixeddeposit/FixedDepositAccountHelper.java    |   7 +
 .../infrastructure/core/api/JsonCommand.java       |  23 +++
 .../AccountAssociationsReadPlatformService.java    |   2 +
 ...AccountAssociationsReadPlatformServiceImpl.java |   5 +
 .../savings/DepositAccountOnClosureType.java       |  19 ++-
 .../portfolio/savings/DepositsApiConstants.java    |   5 +-
 .../api/FixedDepositAccountsApiResource.java       |   7 +-
 .../savings/data/DepositAccountDataValidator.java  |  29 ++++
 .../savings/data/FixedDepositAccountData.java      | 101 +++++++-----
 .../savings/domain/DepositAccountAssembler.java    |  12 +-
 .../domain/DepositAccountDomainService.java        |   9 +-
 .../domain/DepositAccountDomainServiceJpa.java     |  88 +++++++++-
 .../domain/DepositAccountTermAndPreClosure.java    |  37 ++++-
 .../savings/domain/FixedDepositAccount.java        |  30 ++++
 .../savings/domain/RecurringDepositAccount.java    |   4 +
 .../portfolio/savings/domain/SavingsAccount.java   |   1 -
 .../DepositAccountReadPlatformServiceImpl.java     |  19 ++-
 ...countWritePlatformServiceJpaRepositoryImpl.java |  39 ++++-
 .../DepositsDropdownReadPlatformService.java       |   2 +
 .../DepositsDropdownReadPlatformServiceImpl.java   |  12 ++
 .../savings/service/SavingsEnumerations.java       |  11 +-
 .../V358__fixed_deposit_rollover_transfer.sql      |  21 +++
 23 files changed, 597 insertions(+), 66 deletions(-)

diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/FixedDepositTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/FixedDepositTest.java
index 815c485..dc06538 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/FixedDepositTest.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/FixedDepositTest.java
@@ -2400,6 +2400,175 @@ public class FixedDepositTest {
         Assert.assertEquals("Verifying Pre-Closure maturity amount", expectedPrematureAmount, maturityAmount);
     }
 
+    /***
+     * Test case for Fixed Deposit Account rollover with maturity
+     * instruction as re invest maturity amount(principal+interest)
+     */
+    @Test
+    public void testFixedDepositAccountWithRolloverMaturityAmount() {
+        this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
+        this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
+        this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
+
+        /***
+         * Create GL Accounts for product account mapping
+         */
+        final Account assetAccount = this.accountHelper.createAssetAccount();
+        final Account incomeAccount = this.accountHelper.createIncomeAccount();
+        final Account expenseAccount = this.accountHelper.createExpenseAccount();
+        final Account liabilityAccount = this.accountHelper.createLiabilityAccount();
+
+        DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
+        DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
+        DateFormat currentDateFormat = new SimpleDateFormat("dd");
+
+        Calendar todaysDate = Calendar.getInstance();
+        todaysDate.add(Calendar.MONTH, -3);
+        final String VALID_FROM = dateFormat.format(todaysDate.getTime());
+        todaysDate.add(Calendar.YEAR, 10);
+        final String VALID_TO = dateFormat.format(todaysDate.getTime());
+
+        todaysDate = Calendar.getInstance();
+        todaysDate.add(Calendar.MONTH, -1);
+        final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
+        final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
+        final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
+        final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime());
+
+        Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
+        Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE);
+        Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1;
+        todaysDate.add(Calendar.DATE, numberOfDaysLeft);
+        final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime());
+        final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime());
+
+        Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
+        Assert.assertNotNull(clientId);
+
+        /***
+         * Create FD product with CashBased accounting enabled
+         */
+        final String accountingRule = CASH_BASED;
+        Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, liabilityAccount,
+                incomeAccount, expenseAccount);
+        Assert.assertNotNull(fixedDepositProductId);
+
+        /***
+         * Set  maturityInstructionId as  re-invest principal+interest
+         * */
+        final Integer maturityInstructionId = 300;
+
+        /***
+         * Apply for FD account with created product and verify status
+         */
+        Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), SUBMITTED_ON_DATE,
+                WHOLE_TERM, maturityInstructionId);
+
+        Assert.assertNotNull(fixedDepositAccountId);
+
+        HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
+                this.responseSpec, fixedDepositAccountId.toString());
+        FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
+
+        /***
+         * Approve the FD account and verify whether account is approved
+         */
+        fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
+        FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
+
+        /***
+         * Activate the FD Account and verify whether account is activated
+         */
+        fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE);
+        FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap);
+    }
+
+
+    /***
+     * Test case for Fixed Deposit Account rollover with maturity
+     * instruction as re invest principal only
+     */
+    @Test
+    public void testFixedDepositAccountWithRolloverPrincipal() {
+        this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
+        this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
+        this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
+
+        /***
+         * Create GL Accounts for product account mapping
+         */
+        final Account assetAccount = this.accountHelper.createAssetAccount();
+        final Account incomeAccount = this.accountHelper.createIncomeAccount();
+        final Account expenseAccount = this.accountHelper.createExpenseAccount();
+        final Account liabilityAccount = this.accountHelper.createLiabilityAccount();
+
+        DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
+        DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
+        DateFormat currentDateFormat = new SimpleDateFormat("dd");
+
+        Calendar todaysDate = Calendar.getInstance();
+        todaysDate.add(Calendar.MONTH, -3);
+        final String VALID_FROM = dateFormat.format(todaysDate.getTime());
+        todaysDate.add(Calendar.YEAR, 10);
+        final String VALID_TO = dateFormat.format(todaysDate.getTime());
+
+        todaysDate = Calendar.getInstance();
+        todaysDate.add(Calendar.MONTH, -1);
+        final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
+        final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
+        final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
+        final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime());
+
+        Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
+        Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE);
+        Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1;
+        todaysDate.add(Calendar.DATE, numberOfDaysLeft);
+        final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime());
+        final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime());
+
+        Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
+        Assert.assertNotNull(clientId);
+
+        /***
+         * Create FD product with CashBased accounting enabled
+         */
+        final String accountingRule = CASH_BASED;
+        Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, liabilityAccount,
+                incomeAccount, expenseAccount);
+        Assert.assertNotNull(fixedDepositProductId);
+
+        /***
+         * Set  maturityInstructionId as  re-invest principal
+         * */
+        final Integer maturityInstructionId = 400;
+
+        /***
+         * Apply for FD account with created product and verify status
+         */
+        Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), SUBMITTED_ON_DATE,
+                WHOLE_TERM, maturityInstructionId);
+
+        Assert.assertNotNull(fixedDepositAccountId);
+
+        HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
+                this.responseSpec, fixedDepositAccountId.toString());
+        FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
+
+        /***
+         * Approve the FD account and verify whether account is approved
+         */
+        fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
+        FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
+
+        /***
+         * Activate the FD Account and verify whether account is activated
+         */
+        fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE);
+        FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap);
+    }
+
     private Integer createFixedDepositProduct(final String validFrom, final String validTo, final String accountingRule,
             Account... accounts) {
         LOG.info("------------------------------CREATING NEW FIXED DEPOSIT PRODUCT ---------------------------------------");
@@ -2471,6 +2640,17 @@ public class FixedDepositTest {
     }
 
     private Integer applyForFixedDepositApplication(final String clientID, final String productID, final String submittedOnDate,
+                                                    final String penalInterestType, final Integer maturityInstructionId) {
+        LOG.info("--------------------------------APPLYING FOR FIXED DEPOSIT ACCOUNT --------------------------------");
+        final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec) //
+                .withSubmittedOnDate(submittedOnDate)
+                .withMaturityInstructionId(maturityInstructionId)
+                .build(clientID, productID, penalInterestType);
+        return this.fixedDepositAccountHelper
+                .applyFixedDepositApplication(fixedDepositApplicationJSON, this.requestSpec, this.responseSpec);
+    }
+
+    private Integer applyForFixedDepositApplication(final String clientID, final String productID, final String submittedOnDate,
             final String penalInterestType, final String depositAmount, final String depositPeriod) {
         LOG.info("--------------------------------APPLYING FOR FIXED DEPOSIT ACCOUNT --------------------------------");
         final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec)
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java
index ded5afb..fa4c50b 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java
@@ -96,6 +96,7 @@ public class FixedDepositAccountHelper {
     private String submittedOnDate = "";
     private String savingsId = null;
     private boolean transferInterest = false;
+    private Integer maturityInstructionId;
 
     public String build(final String clientId, final String productId, final String penalInterestType) {
         final HashMap<String, Object> map = new HashMap<>();
@@ -127,6 +128,7 @@ public class FixedDepositAccountHelper {
         map.put("submittedOnDate", this.submittedOnDate);
         map.put("linkAccountId", savingsId);
         map.put("transferInterestToSavings", transferInterest);
+        map.put("maturityInstructionId", maturityInstructionId);
 
         String fixedDepositAccountJson = new Gson().toJson(map);
         LOG.info("{}", fixedDepositAccountJson);
@@ -489,4 +491,9 @@ public class FixedDepositAccountHelper {
         }
         return this.newDepositAmount;
     }
+
+    public FixedDepositAccountHelper withMaturityInstructionId(Integer maturityInstructionId){
+        this.maturityInstructionId = maturityInstructionId;
+        return this;
+    }
 }
\ No newline at end of file
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java
index 7ca8d3a..5008fde 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java
@@ -131,6 +131,10 @@ public final class JsonCommand {
         return new JsonCommand(resourceId, parsedCommand);
     }
 
+    public static JsonCommand fromJsonElement(final Long resourceId, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper) {
+        return new JsonCommand(resourceId, parsedCommand, fromApiJsonHelper);
+    }
+
     public JsonCommand(final Long resourceId, final JsonElement parsedCommand) {
         this.parsedCommand = parsedCommand;
         this.resourceId = resourceId;
@@ -150,6 +154,25 @@ public final class JsonCommand {
         this.organisationCreditBureauId=null;
     }
 
+    public JsonCommand(final Long resourceId, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper) {
+        this.parsedCommand = parsedCommand;
+        this.resourceId = resourceId;
+        this.commandId = null;
+        this.jsonCommand = null;
+        this.fromApiJsonHelper = fromApiJsonHelper;
+        this.entityName = null;
+        this.subresourceId = null;
+        this.groupId = null;
+        this.clientId = null;
+        this.loanId = null;
+        this.savingsId = null;
+        this.transactionId = null;
+        this.url = null;
+        this.productId = null;
+        this.creditBureauId=null;
+        this.organisationCreditBureauId=null;
+    }
+
     public Long getOrganisationCreditBureauId() {
         return this.organisationCreditBureauId;
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformService.java
index aad6f34..2ae6eda 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformService.java
@@ -31,4 +31,6 @@ public interface AccountAssociationsReadPlatformService {
     public PortfolioAccountData retriveSavingsLinkedAssociation(final Long savingsId);
 
     public Collection<AccountAssociationsData> retriveLoanAssociations(Long loanId, Integer associationType);
+
+    PortfolioAccountData retriveSavingsAccount(Long savingsId);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformServiceImpl.java
index 8c0bfa4..9f6a9bb 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountAssociationsReadPlatformServiceImpl.java
@@ -191,4 +191,9 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
         }
 
     }
+    @Override
+    public PortfolioAccountData retriveSavingsAccount(final Long savingsId){
+        String accountNo = jdbcTemplate.queryForObject("select account_no from m_savings_account where id = ?", String.class, savingsId);
+        return PortfolioAccountData.lookup(savingsId, accountNo);
+    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java
index 29ccd73..fc7a2dc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java
@@ -32,7 +32,8 @@ public enum DepositAccountOnClosureType {
     INVALID(0, "depositAccountClosureType.invalid"), //
     WITHDRAW_DEPOSIT(100, "depositAccountClosureType.withdrawDeposit"), //
     TRANSFER_TO_SAVINGS(200, "depositAccountClosureType.transferToSavings"), //
-    REINVEST(300, "depositAccountClosureType.reinvest"); //
+    REINVEST_PRINCIPAL_AND_INTEREST(300, "depositAccountClosureType.reinvestPrincipalAndInterest"),
+    REINVEST_PRINCIPAL_ONLY(400, "depositAccountClosureType.reinvestPrincipalOnly"); //
 
     private final Integer value;
     private final String code;
@@ -63,7 +64,10 @@ public enum DepositAccountOnClosureType {
                 accountOnClosureType = DepositAccountOnClosureType.TRANSFER_TO_SAVINGS;
             break;
             case 300:
-                accountOnClosureType = DepositAccountOnClosureType.REINVEST;
+                accountOnClosureType = DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST;
+            break;
+            case 400:
+                accountOnClosureType = DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY;
             break;
         }
         return accountOnClosureType;
@@ -78,7 +82,16 @@ public enum DepositAccountOnClosureType {
     }
 
     public boolean isReinvest() {
-        return this.value.equals(DepositAccountOnClosureType.REINVEST.getValue());
+        return this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST.getValue()) ||
+                       this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY.getValue());
+    }
+
+    public boolean isReinvestPrincipal() {
+        return this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY.getValue());
+    }
+
+    public boolean isReinvestPrincipalAndInterest() {
+        return this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST.getValue());
     }
 
     public boolean isInvalid() {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java
index b667fcc..44266f1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java
@@ -190,6 +190,8 @@ public class DepositsApiConstants {
     public static final String transferDescriptionParamName = "transferDescription";
     public static final String toSavingsAccountIdParamName = "toSavingsAccountId";
     public static final String savingsAccounts = "savingsAccounts";
+    public static final String maturityInstructionIdParamName = "maturityInstructionId";
+    public static final String transferToSavingsIdParamName = "transferToSavingsId";
 
     public static final String preMatureCloseOnDateParamName = "preMatureCloseOnDate";
 
@@ -298,7 +300,8 @@ public class DepositsApiConstants {
                     interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName,
                     lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, chargesParamName,
                     chartsParamName, depositAmountParamName, depositPeriodParamName, depositPeriodFrequencyIdParamName,
-                    savingsAccounts, expectedFirstDepositOnDateParamName, SavingsApiConstants.withHoldTaxParamName));
+                    savingsAccounts, expectedFirstDepositOnDateParamName, SavingsApiConstants.withHoldTaxParamName,
+                    maturityInstructionIdParamName, transferToSavingsIdParamName));
 
     public static final Set<String> FIXED_DEPOSIT_ACCOUNT_REQUEST_DATA_PARAMETERS = fixedDepositAccountRequestData();
     public static final Set<String> FIXED_DEPOSIT_ACCOUNT_RESPONSE_DATA_PARAMETERS = fixedDepositAccountResponseData();
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java
index c8ffc35..fa67b79 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java
@@ -239,6 +239,7 @@ public class FixedDepositAccountsApiResource {
         Collection<SavingsAccountTransactionData> transactions = null;
         Collection<SavingsAccountChargeData> charges = null;
         PortfolioAccountData linkedAccount = null;
+        PortfolioAccountData transferToSavingsAccount = null;
 
         final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
         if (!associationParameters.isEmpty()) {
@@ -272,6 +273,10 @@ public class FixedDepositAccountsApiResource {
             }
         }
 
+        if(savingsAccount.getTransferToSavingsId() !=null){
+            transferToSavingsAccount = this.accountAssociationsReadPlatformService.retriveSavingsAccount(savingsAccount.getTransferToSavingsId());
+        }
+
         FixedDepositAccountData templateData = null;
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
 
@@ -281,7 +286,7 @@ public class FixedDepositAccountsApiResource {
                     staffInSelectedOfficeOnly);
         }
 
-        return FixedDepositAccountData.associationsAndTemplate(savingsAccount, templateData, transactions, charges, linkedAccount);
+        return FixedDepositAccountData.associationsAndTemplate(savingsAccount, templateData, transactions, charges, linkedAccount, transferToSavingsAccount);
     }
 
     @PUT
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java
index b95c6c7..cc0a1bf 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java
@@ -29,6 +29,7 @@ import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isCalen
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isMandatoryDepositParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.linkedAccountParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.mandatoryRecommendedDepositAmountParamName;
+import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maturityInstructionIdParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermTypeIdParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepositTermParamName;
@@ -39,6 +40,7 @@ import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClos
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.recurringFrequencyParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.recurringFrequencyTypeParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
+import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferToSavingsIdParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountNoParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName;
@@ -77,6 +79,7 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.savings.DepositAccountOnClosureType;
 import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.DepositsApiConstants;
 import org.apache.fineract.portfolio.savings.PreClosurePenalInterestOnType;
@@ -308,6 +311,19 @@ public class DepositAccountDataValidator {
         } else {
             baseDataValidator.reset().parameter(linkedAccountParamName).value(linkAccountId).ignoreIfNull().longGreaterThanZero();
         }
+
+        if (this.fromApiJsonHelper.parameterExists(maturityInstructionIdParamName, element)) {
+            final Integer depositRolloverId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
+                    maturityInstructionIdParamName, element);
+            baseDataValidator.reset().parameter(maturityInstructionIdParamName).value(depositRolloverId).notNull()
+                    .isOneOfTheseValues(DepositAccountOnClosureType.integerValues());
+
+            if(depositRolloverId.equals(DepositAccountOnClosureType.TRANSFER_TO_SAVINGS.getValue())){
+                final Long transferToSavingsId = this.fromApiJsonHelper.extractLongNamed(
+                        transferToSavingsIdParamName, element);
+                baseDataValidator.reset().parameter(transferToSavingsIdParamName).value(transferToSavingsId).notNull().longGreaterThanZero();
+            }
+        }
     }
 
     private void validateDepositDetailsForUpdate(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
@@ -439,6 +455,19 @@ public class DepositAccountDataValidator {
             }
         }
 
+        if (this.fromApiJsonHelper.parameterExists(maturityInstructionIdParamName, element)) {
+            final Integer depositRolloverId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
+                    maturityInstructionIdParamName, element);
+            baseDataValidator.reset().parameter(maturityInstructionIdParamName).value(depositRolloverId).notNull()
+                    .isOneOfTheseValues(DepositAccountOnClosureType.integerValues());
+
+            if(depositRolloverId.equals(DepositAccountOnClosureType.TRANSFER_TO_SAVINGS.getValue())){
+                final Long transferToSavingsId = this.fromApiJsonHelper.extractLongNamed(
+                        transferToSavingsIdParamName, element);
+                baseDataValidator.reset().parameter(transferToSavingsIdParamName).value(transferToSavingsId).notNull().longGreaterThanZero();
+            }
+        }
+
     }
 
     private void validatePreClosureDetailForSubmit(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java
index eb7a74d..63fccc1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java
@@ -53,12 +53,14 @@ public class FixedDepositAccountData extends DepositAccountData {
     private Integer depositPeriod;
     private EnumOptionData depositPeriodFrequency;
     private BigDecimal activationCharge;
+    private Long transferToSavingsId;
 
     // used for account close
     private EnumOptionData onAccountClosure;
 
     private final PortfolioAccountData linkedAccount;
     private final Boolean transferInterestToSavings;
+    private final PortfolioAccountData transferToSavingsAccount;
 
     private Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions;
     private Collection<EnumOptionData> periodFrequencyTypeOptions;
@@ -67,6 +69,7 @@ public class FixedDepositAccountData extends DepositAccountData {
     // for account close
     private Collection<EnumOptionData> onAccountClosureOptions;
     private Collection<PaymentTypeData> paymentTypeOptions;
+    private final Collection<EnumOptionData> maturityInstructionOptions;
 
     //import fields
     private transient Integer rowIndex;
@@ -114,6 +117,7 @@ public class FixedDepositAccountData extends DepositAccountData {
         this.activationCharge = null;
         this.onAccountClosure = null;
         this.linkedAccount = null;
+        this.transferToSavingsAccount = null;
         this.transferInterestToSavings = null;
         this.preClosurePenalInterestOnTypeOptions = null;
         this.periodFrequencyTypeOptions = null;
@@ -125,6 +129,7 @@ public class FixedDepositAccountData extends DepositAccountData {
         this.locale= locale;
         this.submittedOnDate = submittedOnDate;
         this.depositPeriodFrequencyId = depositPeriodFrequencyId;
+        this.maturityInstructionOptions = null;
     }
 
     public Integer getRowIndex() {
@@ -136,11 +141,14 @@ public class FixedDepositAccountData extends DepositAccountData {
             final Integer maxDepositTerm, final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType,
             final Integer inMultiplesOfDepositTerm, final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount,
             final BigDecimal maturityAmount, final LocalDate maturityDate, final Integer depositPeriod,
-            final EnumOptionData depositPeriodFrequency, final EnumOptionData onAccountClosure, final Boolean transferInterestToSavings) {
+            final EnumOptionData depositPeriodFrequency, final EnumOptionData onAccountClosure, final Boolean transferInterestToSavings,
+            final Long transferToSavingsId) {
 
         final PortfolioAccountData linkedAccount = null;
+        final PortfolioAccountData transferToSavingsAccount = null;
         final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
         final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
+        final Collection<EnumOptionData> maturityInstructionOptions = null;
 
         final EnumOptionData depositType = SavingsEnumerations.depositType(DepositAccountType.FIXED_DEPOSIT.getValue());
         final Collection<EnumOptionData> onAccountClosureOptions = null;
@@ -166,7 +174,7 @@ public class FixedDepositAccountData extends DepositAccountData {
                 maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate,
                 depositPeriod, depositPeriodFrequency, periodFrequencyTypeOptions, depositType, onAccountClosure, onAccountClosureOptions,
                 paymentTypeOptions, savingsAccountDatas, linkedAccount, transferInterestToSavings, depositAccountData.withHoldTax,
-                depositAccountData.taxGroup);
+                depositAccountData.taxGroup, maturityInstructionOptions, transferToSavingsId, transferToSavingsAccount);
     }
 
     public static FixedDepositAccountData withInterestChart(final FixedDepositAccountData account,
@@ -187,12 +195,13 @@ public class FixedDepositAccountData extends DepositAccountData {
                 account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
                 account.depositPeriod, account.depositPeriodFrequency, account.periodFrequencyTypeOptions, account.depositType,
                 account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts,
-                account.linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup);
+                account.linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup, account.maturityInstructionOptions,
+                account.transferToSavingsId, account.transferToSavingsAccount);
     }
 
     public static FixedDepositAccountData associationsAndTemplate(final FixedDepositAccountData account, FixedDepositAccountData template,
             final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsAccountChargeData> charges,
-            final PortfolioAccountData linkedAccount) {
+            final PortfolioAccountData linkedAccount, PortfolioAccountData transferToSavingsAccount ) {
 
         if (template == null) {
             template = account;
@@ -214,7 +223,8 @@ public class FixedDepositAccountData extends DepositAccountData {
                 account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
                 account.depositPeriod, account.depositPeriodFrequency, template.periodFrequencyTypeOptions, account.depositType,
                 account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, template.savingsAccounts,
-                linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup);
+                linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup, account.maturityInstructionOptions,
+                account.transferToSavingsId, transferToSavingsAccount);
     }
 
     public static FixedDepositAccountData withTemplateOptions(final FixedDepositAccountData account,
@@ -226,7 +236,8 @@ public class FixedDepositAccountData extends DepositAccountData {
             final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
             final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsAccountChargeData> charges,
             final Collection<ChargeData> chargeOptions, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
-            final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<SavingsAccountData> savingsAccounts) {
+            final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<SavingsAccountData> savingsAccounts,
+            final Collection<EnumOptionData> maturityInstructionOptions) {
 
         return new FixedDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
                 account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
@@ -243,7 +254,8 @@ public class FixedDepositAccountData extends DepositAccountData {
                 account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
                 account.depositPeriod, account.depositPeriodFrequency, periodFrequencyTypeOptions, account.depositType,
                 account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, savingsAccounts,
-                account.linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup);
+                account.linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup, maturityInstructionOptions,
+                account.transferToSavingsId, account.transferToSavingsAccount);
     }
 
     public static FixedDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
@@ -304,6 +316,7 @@ public class FixedDepositAccountData extends DepositAccountData {
         final EnumOptionData depositPeriodFrequency = null;
         final EnumOptionData onAccountClosure = null;
         final PortfolioAccountData linkedAccount = null;
+        final PortfolioAccountData transferToSavingsAccount = null;
         final Boolean transferInterestToSavings = null;
         final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
         final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
@@ -312,6 +325,8 @@ public class FixedDepositAccountData extends DepositAccountData {
         final Collection<EnumOptionData> onAccountClosureOptions = null;
         final Collection<PaymentTypeData> paymentTypeOptions = null;
         final Collection<SavingsAccountData> savingsAccountDatas = null;
+        final Collection<EnumOptionData> maturityInstructionOptions = null;
+        final Long transferToSavingsId = null;
 
         return new FixedDepositAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
                 fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
@@ -324,7 +339,7 @@ public class FixedDepositAccountData extends DepositAccountData {
                 maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
                 depositAmount, maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, periodFrequencyTypeOptions,
                 depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount,
-                transferInterestToSavings, withHoldTax, taxGroup);
+                transferInterestToSavings, withHoldTax, taxGroup, maturityInstructionOptions, transferToSavingsId, transferToSavingsAccount);
     }
 
     public static FixedDepositAccountData preClosureDetails(final Long accountId, BigDecimal maturityAmount,
@@ -393,6 +408,9 @@ public class FixedDepositAccountData extends DepositAccountData {
         final PortfolioAccountData linkedAccount = null;
         final boolean withHoldTax = false;
         final TaxGroupData taxGroup = null;
+        final Collection<EnumOptionData> maturityInstructionOptions = null;
+        final Long transferToSavingsId = null;
+        final PortfolioAccountData transferToSavingsAccount = null;
 
         return new FixedDepositAccountData(accountId, accountNo, externalId, groupId, groupName, clientId, clientName, productId,
                 productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
@@ -405,7 +423,7 @@ public class FixedDepositAccountData extends DepositAccountData {
                 maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
                 depositAmount, maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, periodFrequencyTypeOptions,
                 depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount,
-                transferInterestToSavings, withHoldTax, taxGroup);
+                transferInterestToSavings, withHoldTax, taxGroup, maturityInstructionOptions, transferToSavingsId, transferToSavingsAccount);
     }
 
     public static FixedDepositAccountData withClosureTemplateDetails(final FixedDepositAccountData account,
@@ -428,38 +446,40 @@ public class FixedDepositAccountData extends DepositAccountData {
                 account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
                 account.depositPeriod, account.depositPeriodFrequency, account.periodFrequencyTypeOptions, account.depositType,
                 account.onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, account.linkedAccount,
-                account.transferInterestToSavings, account.withHoldTax, account.taxGroup);
+                account.transferInterestToSavings, account.withHoldTax, account.taxGroup, account.maturityInstructionOptions,
+                account.transferToSavingsId, account.transferToSavingsAccount);
 
     }
 
     private FixedDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId,
-            final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
-            final Long fieldofficerId, final String fieldofficerName, final SavingsAccountStatusEnumData status,
-            final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate,
-            final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType,
-            final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
-            final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
-            final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
-            final BigDecimal minBalanceForInterestCalculation, final SavingsAccountSummaryData summary,
-            final Collection<SavingsAccountTransactionData> transactions, final Collection<DepositProductData> productOptions,
-            final Collection<StaffData> fieldOfficerOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
-            final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
-            final Collection<EnumOptionData> interestCalculationTypeOptions,
-            final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
-            final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
-            final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions,
-            final DepositAccountInterestRateChartData accountChart, final DepositAccountInterestRateChartData chartTemplate,
-            final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
-            final EnumOptionData preClosurePenalInterestOnType, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
-            final Integer minDepositTerm, final Integer maxDepositTerm, final EnumOptionData minDepositTermType,
-            final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm,
-            final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount, final BigDecimal maturityAmount,
-            final LocalDate maturityDate, final Integer depositPeriod, final EnumOptionData depositPeriodFrequency,
-            final Collection<EnumOptionData> periodFrequencyTypeOptions, final EnumOptionData depositType,
-            final EnumOptionData onAccountClosure, final Collection<EnumOptionData> onAccountClosureOptions,
-            final Collection<PaymentTypeData> paymentTypeOptions, final Collection<SavingsAccountData> savingsAccountDatas,
-            final PortfolioAccountData linkedAccount, final Boolean transferInterestToSavings, final boolean withHoldTax,
-            final TaxGroupData taxGroup) {
+                                    final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
+                                    final Long fieldofficerId, final String fieldofficerName, final SavingsAccountStatusEnumData status,
+                                    final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate,
+                                    final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType,
+                                    final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
+                                    final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
+                                    final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
+                                    final BigDecimal minBalanceForInterestCalculation, final SavingsAccountSummaryData summary,
+                                    final Collection<SavingsAccountTransactionData> transactions, final Collection<DepositProductData> productOptions,
+                                    final Collection<StaffData> fieldOfficerOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
+                                    final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
+                                    final Collection<EnumOptionData> interestCalculationTypeOptions,
+                                    final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
+                                    final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
+                                    final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions,
+                                    final DepositAccountInterestRateChartData accountChart, final DepositAccountInterestRateChartData chartTemplate,
+                                    final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
+                                    final EnumOptionData preClosurePenalInterestOnType, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
+                                    final Integer minDepositTerm, final Integer maxDepositTerm, final EnumOptionData minDepositTermType,
+                                    final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm,
+                                    final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount, final BigDecimal maturityAmount,
+                                    final LocalDate maturityDate, final Integer depositPeriod, final EnumOptionData depositPeriodFrequency,
+                                    final Collection<EnumOptionData> periodFrequencyTypeOptions, final EnumOptionData depositType,
+                                    final EnumOptionData onAccountClosure, final Collection<EnumOptionData> onAccountClosureOptions,
+                                    final Collection<PaymentTypeData> paymentTypeOptions, final Collection<SavingsAccountData> savingsAccountDatas,
+                                    final PortfolioAccountData linkedAccount, final Boolean transferInterestToSavings, final boolean withHoldTax,
+                                    final TaxGroupData taxGroup, final Collection<EnumOptionData> maturityInstructionOptions, final Long transferToSavingsId,
+                                    final PortfolioAccountData transferToSavingsAccount) {
 
         super(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldofficerId,
                 fieldofficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType,
@@ -485,6 +505,7 @@ public class FixedDepositAccountData extends DepositAccountData {
         this.depositPeriodFrequency = depositPeriodFrequency;
         this.onAccountClosure = onAccountClosure;
         this.linkedAccount = linkedAccount;
+        this.transferToSavingsAccount = transferToSavingsAccount;
         this.transferInterestToSavings = transferInterestToSavings;
 
         // template
@@ -495,6 +516,8 @@ public class FixedDepositAccountData extends DepositAccountData {
         this.onAccountClosureOptions = onAccountClosureOptions;
         this.paymentTypeOptions = paymentTypeOptions;
         this.savingsAccounts = savingsAccountDatas;
+        this.maturityInstructionOptions = maturityInstructionOptions;
+        this.transferToSavingsId = transferToSavingsId;
     }
 
     @Override
@@ -521,4 +544,8 @@ public class FixedDepositAccountData extends DepositAccountData {
     public void setActivationCharge(BigDecimal activationCharge) {
         this.activationCharge = activationCharge;
     }
+
+    public Long getTransferToSavingsId() {
+        return transferToSavingsId;
+    }
 }
\ No newline at end of file
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountAssembler.java
index 6591ec3..283bfd5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountAssembler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountAssembler.java
@@ -32,7 +32,9 @@ import static org.apache.fineract.portfolio.savings.DepositsApiConstants.expecte
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isCalendarInheritedParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isMandatoryDepositParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.mandatoryRecommendedDepositAmountParamName;
+import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maturityInstructionIdParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
+import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferToSavingsIdParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountNoParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.clientIdParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.externalIdParamName;
@@ -298,6 +300,10 @@ public class DepositAccountAssembler {
                 throw new UnsupportedParameterException(Arrays.asList(withHoldTaxParamName));
             }
         }
+        Integer depositRolloverId =  null;
+        if(command.parameterExists(maturityInstructionIdParamName)){
+            depositRolloverId = command.integerValueOfParameterNamed(maturityInstructionIdParamName);
+        }
 
         SavingsAccount account = null;
         if (depositAccountType.isFixedDeposit()) {
@@ -375,10 +381,12 @@ public class DepositAccountAssembler {
         final BigDecimal maturityAmount = null;// calculated and updated in
                                                // account
         final LocalDate maturityDate = null;// calculated and updated in account
-        final DepositAccountOnClosureType accountOnClosureType = null;
+        final Integer accountOnClosureTypeId = command.integerValueOfParameterNamed(maturityInstructionIdParamName);
+        final DepositAccountOnClosureType accountOnClosureType = accountOnClosureTypeId != null ? DepositAccountOnClosureType.fromInt(accountOnClosureTypeId) :null;
+        final Long transferToSavingsId  = command.longValueOfParameterNamed(transferToSavingsIdParamName);
         return DepositAccountTermAndPreClosure.createNew(updatedProductPreClosure, updatedProductTerm, account, depositAmount,
                 maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType,
-                trasferInterest);
+                trasferInterest, transferToSavingsId);
     }
 
     public DepositAccountRecurringDetail assembleAccountRecurringDetail(final JsonCommand command,
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java
index 08f602e..40d4a5f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java
@@ -25,6 +25,7 @@ import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.joda.time.LocalDate;
 import org.joda.time.format.DateTimeFormatter;
+import org.springframework.transaction.annotation.Transactional;
 
 public interface DepositAccountDomainService {
 
@@ -43,8 +44,14 @@ public interface DepositAccountDomainService {
     Long handleFDAccountClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command,
             LocalDate tenantsTodayDate, Map<String, Object> changes);
 
+    @Transactional
+    Long handleFDAccountMaturityClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user,
+                                        LocalDate tenantsTodayDate, DateTimeFormatter fmt,
+                                        LocalDate closedDate, Integer onAccountClosureId,
+                                        Long toSavingsId, String transferDescription, Map<String, Object> changes);
+
     Long handleRDAccountClosure(RecurringDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command,
-            LocalDate tenantsTodayDate, Map<String, Object> changes);
+                                LocalDate tenantsTodayDate, Map<String, Object> changes);
 
     Long handleFDAccountPreMatureClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command,
             LocalDate tenantsTodayDate, Map<String, Object> changes);
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 e8b5d7f..c9a5f97 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
@@ -189,7 +189,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
     @Transactional
     @Override
     public Long handleFDAccountClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
-            final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
+                                       final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
 
         final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
                 .isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -263,6 +263,85 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
 
     @Transactional
     @Override
+    public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
+                                               final LocalDate tenantsTodayDate, final DateTimeFormatter fmt,
+                                               final LocalDate closedDate, final Integer onAccountClosureId,
+                                               final Long toSavingsId, final String transferDescription,
+                                               Map<String, Object> changes) {
+
+        final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+                .isSavingsInterestPostingAtCurrentPeriodEnd();
+        final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
+
+        boolean isRegularTransaction = false;
+        boolean isAccountTransfer = false;
+        final boolean isPreMatureClosure = false;
+        final Set<Long> existingTransactionIds = new HashSet<>();
+        final Set<Long> existingReversedTransactionIds = new HashSet<>();
+        /***
+         * Update account transactionIds for post journal entries.
+         */
+        updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
+
+        final MathContext mc = MathContext.DECIMAL64;
+        Long savingsTransactionId = null;
+        account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
+        final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId);
+        if (onClosureType.isReinvest()) {
+            BigDecimal reInvestAmount;
+            if(onClosureType.isReinvestPrincipal())
+                reInvestAmount = account.getDepositAmount();
+            else
+                reInvestAmount = account.getAccountBalance();
+            FixedDepositAccount reinvestedDeposit = account.reInvest(reInvestAmount);
+            this.depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
+            reinvestedDeposit.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
+                    isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
+
+            this.savingsAccountRepository.save(reinvestedDeposit);
+            autoGenerateAccountNumber(reinvestedDeposit);
+            final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, reInvestAmount,
+                    paymentDetail, false, isRegularTransaction);
+            savingsTransactionId = withdrawal.getId();
+
+            if (onClosureType.isReinvestPrincipalAndInterest()) {
+                account.updateClosedStatus();
+                account.updateOnAccountClosureStatus(onClosureType);
+            }
+            changes.put("reinvestedDepositId", reinvestedDeposit.getId());
+            reinvestedDeposit.approveAndActivateApplication(closedDate.toDate(), user);
+            this.savingsAccountRepository.save(reinvestedDeposit);
+
+        } else if (onClosureType.isTransferToSavings()) {
+            final SavingsAccount toSavingsAccount = this.depositAccountAssembler.assembleFrom(toSavingsId,
+                    DepositAccountType.SAVINGS_DEPOSIT);
+            final boolean isExceptionForBalanceCheck = false;
+            final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(closedDate, account.getAccountBalance(),
+                    PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, null, null, transferDescription, null, fmt, null, null,
+                    null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, null, null, toSavingsAccount, account,
+                    isAccountTransfer, isExceptionForBalanceCheck);
+            this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
+            updateAlreadyPostedTransactions(existingTransactionIds, account);
+            account.updateClosedStatus();
+            account.updateOnAccountClosureStatus(onClosureType);
+        } else {
+            final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(),
+                    paymentDetail, false, isRegularTransaction);
+            savingsTransactionId = withdrawal.getId();
+        }
+
+        //if(!processMaturityInstructionOnly)
+          //  account.close(user, command, tenantsTodayDate, changes);
+
+        this.savingsAccountRepository.save(account);
+
+        postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
+
+        return savingsTransactionId;
+    }
+
+    @Transactional
+    @Override
     public Long handleRDAccountClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
             final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
 
@@ -290,7 +369,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
         final Integer onAccountClosureId = command.integerValueOfParameterNamed(onAccountClosureIdParamName);
         final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId);
         if (onClosureType.isReinvest()) {
-            RecurringDepositAccount reinvestedDeposit = account.reInvest(transactionAmount);
+            BigDecimal reInvestAmount;
+            if(onClosureType.isReinvestPrincipal())
+                reInvestAmount = account.getDepositAmount();
+            else
+                reInvestAmount = account.getAccountBalance();
+            RecurringDepositAccount reinvestedDeposit = account.reInvest(reInvestAmount);
             depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
             this.savingsAccountRepository.save(reinvestedDeposit);
             final CalendarInstance calendarInstance = getCalendarInstance(account, reinvestedDeposit);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountTermAndPreClosure.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountTermAndPreClosure.java
index 3b833a5..f13a1b4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountTermAndPreClosure.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountTermAndPreClosure.java
@@ -24,7 +24,9 @@ import static org.apache.fineract.portfolio.savings.DepositsApiConstants.deposit
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositPeriodParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.expectedFirstDepositOnDateParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.localeParamName;
+import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maturityInstructionIdParamName;
 import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
+import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferToSavingsIdParamName;
 
 import java.math.BigDecimal;
 import java.util.Date;
@@ -90,6 +92,9 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
     @Column(name = "transfer_interest_to_linked_account", nullable = false)
     private boolean transferInterestToLinkedAccount;
 
+    @Column(name = "transfer_to_savings_account_id")
+    private Long transferToSavingsAccountId;
+
     protected DepositAccountTermAndPreClosure() {
         super();
     }
@@ -97,16 +102,16 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
     public static DepositAccountTermAndPreClosure createNew(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
             SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
             Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
-            final DepositAccountOnClosureType accountOnClosureType, Boolean trasferInterest) {
+            final DepositAccountOnClosureType accountOnClosureType, Boolean trasferInterest, Long transferToSavingsId) {
 
         return new DepositAccountTermAndPreClosure(preClosureDetail, depositTermDetail, account, depositAmount, maturityAmount,
-                maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType, trasferInterest);
+                maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType, trasferInterest, transferToSavingsId);
     }
 
     private DepositAccountTermAndPreClosure(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
             SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
             Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
-            final DepositAccountOnClosureType accountOnClosureType, Boolean transferInterest) {
+            final DepositAccountOnClosureType accountOnClosureType, Boolean transferInterest, Long transferToSavingsId) {
         this.depositAmount = depositAmount;
         this.maturityAmount = maturityAmount;
         this.maturityDate = (maturityDate == null) ? null : maturityDate.toDate();
@@ -118,6 +123,7 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
         this.expectedFirstDepositOnDate = expectedFirstDepositOnDate == null ? null : expectedFirstDepositOnDate.toDate();
         this.onAccountClosureType = (accountOnClosureType == null) ? null : accountOnClosureType.getValue();
         this.transferInterestToLinkedAccount = transferInterest;
+        this.transferToSavingsAccountId = transferToSavingsId;
     }
 
     public Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
@@ -158,6 +164,20 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
             this.transferInterestToLinkedAccount = newValue;
         }
 
+        if (command.isChangeInIntegerParameterNamed(maturityInstructionIdParamName, this.onAccountClosureType) || command.integerValueOfParameterNamed(
+                maturityInstructionIdParamName) == null) {
+            final Integer newValue = command.integerValueOfParameterNamed(maturityInstructionIdParamName);
+            actualChanges.put(maturityInstructionIdParamName, newValue);
+            this.onAccountClosureType = newValue != null ? DepositAccountOnClosureType.fromInt(newValue).getValue() : null;
+        }
+
+        if (command.isChangeInLongParameterNamed(transferToSavingsIdParamName, this.transferToSavingsAccountId) || command.integerValueOfParameterNamed(
+                transferToSavingsIdParamName) == null) {
+            final Long newValue = command.longValueOfParameterNamed(transferToSavingsIdParamName);
+            actualChanges.put(transferToSavingsIdParamName, newValue);
+            this.transferToSavingsAccountId = newValue ;
+        }
+
         if (this.preClosureDetail != null) {
             actualChanges.putAll(this.preClosureDetail.update(command, baseDataValidator));
         }
@@ -291,9 +311,10 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
         final Boolean transferInterestToLinkedAccount = false;
 
         final DepositAccountOnClosureType accountOnClosureType = null;
+        final Long transferToSavingsId = null;
         return DepositAccountTermAndPreClosure.createNew(preClosureDetail, depositTermDetail, account, actualDepositAmount, maturityAmount,
                 maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType,
-                transferInterestToLinkedAccount);
+                transferInterestToLinkedAccount, transferToSavingsId);
     }
 
     public void updateExpectedFirstDepositDate(final LocalDate expectedFirstDepositOnDate) {
@@ -311,4 +332,12 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
         }
         return isAfterExpectedFirstDepositDate;
     }
+
+    public Integer getOnAccountClosureType() {
+        return onAccountClosureType;
+    }
+
+    public Long getTransferToSavingsAccountId() {
+        return transferToSavingsAccountId;
+    }
 }
\ No newline at end of file
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 2c909ef..d5e23b9 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
@@ -259,6 +259,8 @@ public class FixedDepositAccount extends SavingsAccount {
         }
     }
 
+
+
     public LocalDate calculateMaturityDate() {
 
         final LocalDate startDate = accountSubmittedOrActivationDate();
@@ -489,6 +491,14 @@ public class FixedDepositAccount extends SavingsAccount {
         // this.savingsAccountTransactionSummaryWrapper, this.transactions);
     }
 
+    public void updateClosedStatus(){
+        this.status = SavingsAccountStatusType.CLOSED.getValue();
+    }
+
+    public void updateOnAccountClosureStatus(DepositAccountOnClosureType onClosureType){
+        this.accountTermAndPreClosure.updateOnAccountClosureStatus(onClosureType);
+    }
+
     public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
         final LocalDate interestPostingUpToDate = maturityDate();
         final MathContext mc = MathContext.DECIMAL64;
@@ -756,6 +766,14 @@ public class FixedDepositAccount extends SavingsAccount {
         return this.accountTermAndPreClosure.isTransferToSavingsOnClosure();
     }
 
+    public Integer getOnAccountClosureId(){
+        return this.accountTermAndPreClosure.getOnAccountClosureType();
+    }
+
+    public Long getTransferToSavingsAccountId() {
+        return this.accountTermAndPreClosure.getTransferToSavingsAccountId();
+    }
+
     public FixedDepositAccount reInvest(BigDecimal depositAmount) {
 
         final DepositAccountTermAndPreClosure newAccountTermAndPreClosure = this.accountTermAndPreClosure.copy(depositAmount);
@@ -830,4 +848,16 @@ public class FixedDepositAccount extends SavingsAccount {
         super.loadLazyCollections();
         this.chart.getId() ;
     }
+
+    public BigDecimal getDepositAmount() {
+        return this.accountTermAndPreClosure.depositAmount();
+    }
+    @Override
+    public BigDecimal getAccountBalance() {
+        return this.summary.getAccountBalance(this.currency).getAmount();
+    }
+    public boolean isMatured(){
+        return SavingsAccountStatusType.MATURED.getValue().equals(this.status);
+    }
+
 }
\ No newline at end of file
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 79d592d..670d53c 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
@@ -1232,4 +1232,8 @@ public class RecurringDepositAccount extends SavingsAccount {
         super.loadLazyCollections();
         this.chart.getId() ;
     }
+
+    public BigDecimal getDepositAmount() {
+        return this.accountTermAndPreClosure.depositAmount();
+    }
 }
\ No newline at end of file
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 c52e676..a1499c1 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
@@ -1433,7 +1433,6 @@ public class SavingsAccount extends AbstractPersistableCustom {
                 baseDataValidator.reset().parameter(withHoldTaxParamName).failWithCode("not.supported.for.this.account");
             }
         }
-
         validateLockinDetails(baseDataValidator);
         esnureOverdraftLimitsSetForOverdraftAccounts();
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java
index 1a70557..55b43fc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java
@@ -378,6 +378,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
             final boolean feeChargesOnly = false;
             final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSavingsProductApplicableCharges(feeChargesOnly);
 
+            final Collection<EnumOptionData> maturityInstructionOptions = this.depositsDropdownReadPlatformService.maturityInstructionOptions();
+
             Collection<StaffData> fieldOfficerOptions = null;
 
             if (officeId != null) {
@@ -405,7 +407,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
             }
 
             // retrieve chart Slabs
-            final InterestRateChartData productChartData = this.productChartReadPlatformService.retrieveActiveChartWithTemplate(productId);
+                final InterestRateChartData productChartData = this.productChartReadPlatformService.retrieveActiveChartWithTemplate(productId);
             final DepositAccountInterestRateChartData accountChart = DepositAccountInterestRateChartData.from(productChartData);
 
             if (depositAccountType.isFixedDeposit()) {
@@ -414,7 +416,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
                         fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
                         interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
                         withdrawalFeeTypeOptions, transactions, charges, chargeOptions, preClosurePenalInterestOnTypeOptions,
-                        periodFrequencyTypeOptions, savingsAccountDatas);
+                        periodFrequencyTypeOptions, savingsAccountDatas, maturityInstructionOptions);
 
                 template = FixedDepositAccountData.withInterestChart((FixedDepositAccountData) template, accountChart);
             } else if (depositAccountType.isRecurringDeposit()) {
@@ -450,6 +452,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
 
             final Collection<SavingsAccountTransactionData> transactions = null;
             final Collection<SavingsAccountChargeData> charges = null;
+                final Collection<EnumOptionData> maturityInstructionOptions = null;
 
             final boolean feeChargesOnly = true;
             final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSavingsProductApplicableCharges(feeChargesOnly);
@@ -462,7 +465,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
                         fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
                         interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
                         withdrawalFeeTypeOptions, transactions, charges, chargeOptions, preClosurePenalInterestOnTypeOptions,
-                        periodFrequencyTypeOptions, savingsAccountDatas);
+                        periodFrequencyTypeOptions, savingsAccountDatas, maturityInstructionOptions);
             } else if (depositAccountType.isRecurringDeposit()) {
 
                 template = RecurringDepositAccountData.withClientTemplate(clientId, clientName, groupId, groupName);
@@ -778,7 +781,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
             sqlBuilder.append("datp.deposit_period as depositPeriod, ");
             sqlBuilder.append("datp.deposit_period_frequency_enum as depositPeriodFrequencyTypeId, ");
             sqlBuilder.append("datp.on_account_closure_enum as onAccountClosureId, ");
-            sqlBuilder.append("datp.transfer_interest_to_linked_account as transferInterestToSavings ");
+            sqlBuilder.append("datp.transfer_interest_to_linked_account as transferInterestToSavings, ");
+            sqlBuilder.append("datp.transfer_to_savings_account_id as transferToSavingsId ");
 
             sqlBuilder.append(super.selectTablesSql());
 
@@ -826,10 +830,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
                     .depositAccountOnClosureType(onAccountClosureId);
             final Boolean transferInterestToSavings = rs.getBoolean("transferInterestToSavings");
 
+            final Long transferToSavingsId = JdbcSupport.getLong(rs, "transferToSavingsId");
+
+
             return FixedDepositAccountData.instance(depositAccountData, preClosurePenalApplicable, preClosurePenalInterest,
                     preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
                     inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
-                    depositPeriodFrequencyType, onAccountClosureType, transferInterestToSavings);
+                    depositPeriodFrequencyType, onAccountClosureType, transferInterestToSavings, transferToSavingsId);
         }
     }
 
@@ -1266,7 +1273,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
             return FixedDepositAccountData.instance(depositAccountData, preClosurePenalApplicable, preClosurePenalInterest,
                     preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
                     inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
-                    depositPeriodFrequencyType, onAccountClosureType, transferInterestToSavings);
+                    depositPeriodFrequencyType, onAccountClosureType, transferInterestToSavings, null);
         }
     }
 
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 c1c5fc5..2e42c5c 100755
--- 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
@@ -28,6 +28,7 @@ import java.math.BigDecimal;
 import java.math.MathContext;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -44,6 +45,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
 import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
@@ -145,6 +147,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
     private final HolidayRepositoryWrapper holidayRepository;
     private final WorkingDaysRepositoryWrapper workingDaysRepository;
     private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
+    private final FromJsonHelper fromApiJsonHelper;
 
     @Autowired
     public DepositAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -164,7 +167,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
             final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
             final DepositAccountReadPlatformService depositAccountReadPlatformService,
             final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService,
-            final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository) {
+            final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
+            final FromJsonHelper fromApiJsonHelper) {
 
         this.context = context;
         this.savingAccountRepositoryWrapper = savingAccountRepositoryWrapper;
@@ -188,6 +192,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
         this.calendarInstanceRepository = calendarInstanceRepository;
         this.configurationDomainService = configurationDomainService;
         this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository;
+        this.fromApiJsonHelper = fromApiJsonHelper;
     }
 
     @Transactional
@@ -798,14 +803,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
         this.depositAccountTransactionDataValidator.validateClosing(command, DepositAccountType.FIXED_DEPOSIT, isPreMatureClose);
 
         final Map<String, Object> changes = new LinkedHashMap<>();
-        final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
+        final PaymentDetail
+                paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
 
         final FixedDepositAccount account = (FixedDepositAccount) this.depositAccountAssembler.assembleFrom(savingsId,
                 DepositAccountType.FIXED_DEPOSIT);
         checkClientOrGroupActive(account);
 
-        this.depositAccountDomainService.handleFDAccountClosure(account, paymentDetail, user, command, DateUtils.getLocalDateOfTenant(),
-                changes);
+        this.depositAccountDomainService.handleFDAccountClosure(account, paymentDetail, user, command, DateUtils.getLocalDateOfTenant(), changes);
 
         final String noteText = command.stringValueOfParameterNamed("note");
         if (StringUtils.isNotBlank(noteText)) {
@@ -1352,6 +1357,32 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
 
         if (depositAccountType.isFixedDeposit()) {
             ((FixedDepositAccount) account).updateMaturityStatus(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
+            FixedDepositAccount fdAccount = ((FixedDepositAccount) account);
+            //handle maturity instructions
+
+            if(fdAccount.isMatured() && (fdAccount.isReinvestOnClosure() || fdAccount.isTransferToSavingsOnClosure())){
+                DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd");
+                Map<String, Object> changes = new HashMap<>();
+                AppUser user = context.authenticatedUser();
+                Long toSavingsId = fdAccount.getTransferToSavingsAccountId();
+                this.depositAccountDomainService.handleFDAccountMaturityClosure(fdAccount, null, user,
+                        fdAccount.maturityDate(), fmt, fdAccount.maturityDate(),
+                        fdAccount.getOnAccountClosureId(), toSavingsId, "Apply maturity instructions", changes);
+
+                if(changes.get("reinvestedDepositId") != null) {
+                    Long reinvestedDepositId = (Long) changes.get("reinvestedDepositId");
+                    Money amountForDeposit = account.activateWithBalance();
+                    final FixedDepositAccount reinvestAccount = (FixedDepositAccount) this.depositAccountAssembler.assembleFrom(reinvestedDepositId,
+                            DepositAccountType.FIXED_DEPOSIT);
+                    Money activationChargeAmount = getActivationCharge(reinvestAccount);
+                    if(activationChargeAmount.isGreaterThanZero()){
+                        payActivationCharge(reinvestAccount, user);
+                        amountForDeposit  = amountForDeposit.plus(activationChargeAmount);
+                    }
+                    this.depositAccountDomainService.handleFDDeposit(reinvestAccount, fmt, fdAccount.maturityDate(),
+                            amountForDeposit.getAmount(), null);
+                }
+            }
         } else if (depositAccountType.isRecurringDeposit()) {
             ((RecurringDepositAccount) account).updateMaturityStatus(isSavingsInterestPostingAtCurrentPeriodEnd,
                     financialYearBeginningMonth);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformService.java
index d186a69..07c041f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformService.java
@@ -27,6 +27,8 @@ public interface DepositsDropdownReadPlatformService {
 
     Collection<EnumOptionData> retrievePreClosurePenalInterestOnTypeOptions();
 
+    Collection<EnumOptionData> maturityInstructionOptions();
+
     /*
      * Collection<EnumOptionData> retrieveDepositTermTypeOptions();
      *
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformServiceImpl.java
index 70ce68f..7c172e0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositsDropdownReadPlatformServiceImpl.java
@@ -18,8 +18,10 @@
  */
 package org.apache.fineract.portfolio.savings.service;
 
+import java.util.Arrays;
 import java.util.Collection;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.portfolio.savings.DepositAccountOnClosureType;
 import org.apache.fineract.portfolio.savings.PreClosurePenalInterestOnType;
 import org.springframework.stereotype.Service;
 
@@ -48,4 +50,14 @@ public class DepositsDropdownReadPlatformServiceImpl implements DepositsDropdown
      * .recurringDepositFrequencyType(SavingsPeriodFrequencyType.values()); }
      */
 
+
+    @Override
+    public Collection<EnumOptionData> maturityInstructionOptions() {
+        return  Arrays.asList(
+            SavingsEnumerations.depositAccountOnClosureType(DepositAccountOnClosureType.WITHDRAW_DEPOSIT),
+            SavingsEnumerations.depositAccountOnClosureType(DepositAccountOnClosureType.TRANSFER_TO_SAVINGS),
+            SavingsEnumerations.depositAccountOnClosureType(DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST),
+            SavingsEnumerations.depositAccountOnClosureType(DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY));
+
+    }
 }
\ No newline at end of file
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 b552cbd..b0b2644 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
@@ -795,10 +795,14 @@ public class SavingsEnumerations {
                 optionData = new EnumOptionData(DepositAccountOnClosureType.TRANSFER_TO_SAVINGS.getValue().longValue(),
                         DepositAccountOnClosureType.TRANSFER_TO_SAVINGS.getCode(), "Transfer to Savings");
             break;
-            case REINVEST:
-                optionData = new EnumOptionData(DepositAccountOnClosureType.REINVEST.getValue().longValue(),
-                        DepositAccountOnClosureType.REINVEST.getCode(), "Re-Invest");
+            case REINVEST_PRINCIPAL_AND_INTEREST:
+                optionData = new EnumOptionData(DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST.getValue().longValue(),
+                        DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST.getCode(), "Re-Invest Maturity Amount");
             break;
+            case REINVEST_PRINCIPAL_ONLY:
+                optionData = new EnumOptionData(DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY.getValue().longValue(),
+                                                DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY.getCode(), "Re-Invest Principal Only");
+                break;
         }
         return optionData;
     }
@@ -835,5 +839,4 @@ public class SavingsEnumerations {
         }
         return optionData;
     }
-
 }
\ No newline at end of file
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V358__fixed_deposit_rollover_transfer.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V358__fixed_deposit_rollover_transfer.sql
new file mode 100644
index 0000000..6bb8300
--- /dev/null
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V358__fixed_deposit_rollover_transfer.sql
@@ -0,0 +1,21 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+alter table m_deposit_account_term_and_preclosure add column transfer_to_savings_account_id bigint(20) DEFAULT NULL,
+add  CONSTRAINT FOREIGN KEY (`transfer_to_savings_account_id`) REFERENCES `m_savings_account` (`id`);
\ No newline at end of file


Mime
View raw message